From b1e6a5fa49d0ce1d3bbf9c256b31663ff2815e8a Mon Sep 17 00:00:00 2001 From: DS_Starter Date: Sun, 11 Oct 2020 19:25:54 +0000 Subject: [PATCH] 76_SMAPortal: contrib 3.6.0 git-svn-id: https://svn.fhem.de/fhem/trunk@22955 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/76_SMAPortal.pm | 425 +++++++++++++++--------- 1 file changed, 274 insertions(+), 151 deletions(-) diff --git a/fhem/contrib/DS_Starter/76_SMAPortal.pm b/fhem/contrib/DS_Starter/76_SMAPortal.pm index 1bda8fefb..4b2fa3942 100644 --- a/fhem/contrib/DS_Starter/76_SMAPortal.pm +++ b/fhem/contrib/DS_Starter/76_SMAPortal.pm @@ -312,6 +312,7 @@ sub Initialize { "providerLevel:multiple-strict,".$prov." ". "showPassInLog:1,0 ". "userAgent ". + "useRelativeNames:1,0 ". "verbose5Data:multiple-strict,none,loginData,".$v5d." ". $readingFnAttributes; @@ -387,7 +388,8 @@ sub Set { ## no critic 'complexity' $setlist = "Unknown argument $opt, choose one of ". "credentials " ; - } else { + } + else { # erweiterte Setlist wenn Credentials gesetzt $setlist = "Unknown argument $opt, choose one of ". "credentials ". @@ -414,9 +416,9 @@ sub Set { ## no critic 'complexity' # Verbraucher schalten $hash->{HELPER}{GETTER} = "none"; $hash->{HELPER}{SETTER} = "$opt:$prop"; - CallInfo($hash); - - } else { + CallInfo($hash); + } + else { my $params = { hash => $hash, name => $name, @@ -458,8 +460,8 @@ sub _setCredentials { ## no critic "not used" delcookiefile ($hash); CallInfo($hash); return "Username and Password saved successfully"; - - } else { + } + else { return "Error while saving Username / Password - see logfile for details"; } @@ -498,22 +500,26 @@ sub _setCreatePortalGraphic { ## no critic "not used" $type = 'pv'; $c = "SMA Sunny Portal Graphics - Forecast Generation"; $color2 = "000000"; # zweite Farbe als schwarz setzen - } elsif ($prop eq "Consumption") { + } + elsif ($prop eq "Consumption") { $htmldev = "SPG2.$name"; # Grafiktyp Consumption (Verbrauch) $type = 'co'; $c = "SMA Sunny Portal Graphics - Forecast Consumption"; $color2 = "000000"; # zweite Farbe als schwarz setzen - } elsif ($prop eq "Generation_Consumption") { + } + elsif ($prop eq "Generation_Consumption") { $htmldev = "SPG3.$name"; # Grafiktyp Generation_Consumption (Erzeugung und Verbrauch) $type = 'pvco'; $c = "SMA Sunny Portal Graphics - Forecast Generation & Consumption"; $color2 = "FF5C82"; # zweite Farbe als rot setzen - } elsif ($prop eq "Differential") { + } + elsif ($prop eq "Differential") { $htmldev = "SPG4.$name"; # Grafiktyp Differential (Differenzanzeige) $type = 'diff'; $c = "SMA Sunny Portal Graphics - Forecast Differential"; $color2 = "FF5C82"; # zweite Farbe als rot setzen - } else { + } + else { return "Invalid portal graphic devicetype ! Use one of \"Generation\", \"Consumption\", \"Generation_Consumption\", \"Differential\". " } @@ -581,8 +587,8 @@ sub Get { $hash->{HELPER}{SETTER} = "none"; CallInfo($hash); - - } elsif ($opt eq "storedCredentials") { + } + elsif ($opt eq "storedCredentials") { if(!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials <username> <password>\"";} # Credentials abrufen my ($success, $username, $password) = getcredentials($hash,0); @@ -591,9 +597,9 @@ sub Get { return "Stored Credentials to access SMA Portal:\n". "========================================\n". "Username: $username, Password: $password\n". - "\n"; - - } else { + "\n"; + } + else { return "$getlist"; } @@ -639,8 +645,9 @@ sub setcredentials { if ($retcode) { Log3($name, 1, "$name - Error while saving the Credentials - $retcode"); $success = 0; - } else { - getcredentials($hash,1); # Credentials nach Speicherung lesen und in RAM laden ($boot=1) + } + else { + getcredentials($hash,1); # Credentials nach Speicherung lesen und in RAM laden ($boot=1) $success = 1; } @@ -671,7 +678,8 @@ sub getcredentials { $hash->{CREDENTIALS} = "Set"; # "Credentials" wird als Statusbit ausgewertet. Wenn nicht gesetzt -> Warnmeldung und keine weitere Verarbeitung $success = 1; } - } else { # boot = 0 -> Credentials aus RAM lesen, decoden und zurückgeben + } + else { # boot = 0 -> Credentials aus RAM lesen, decoden und zurückgeben $credstr = $hash->{HELPER}{".CREDENTIALS"} // $hash->{HELPER}{CREDENTIALS}; # Kompatibilität zu Versionen vor 2.6.1 if($credstr) { @@ -688,8 +696,8 @@ sub getcredentials { my $logpw = AttrVal($name, "showPassInLog", 0) ? $passwd : "********"; Log3($name, 4, "$name - Credentials read from RAM: $username $logpw"); - - } else { + } + else { Log3($name, 1, "$name - Credentials not set in RAM !"); } @@ -723,7 +731,8 @@ sub Attr { delcookiefile ($hash); delete $hash->{MODE}; RemoveInternalTimer($hash); - } else { + } + else { InternalTimer(gettimeofday()+1.0, "FHEM::SMAPortal::CallInfo", $hash, 0); } @@ -771,7 +780,8 @@ sub CallInfo { ## no critic 'complexity' if(!$interval) { $hash->{MODE} = "Manual"; - } else { + } + else { $new = gettimeofday()+$interval; InternalTimer($new, "FHEM::SMAPortal::CallInfo", $hash, 0); # Wiederholungsintervall $hash->{MODE} = "Automatic - next polltime: ".FmtTime($new); @@ -984,7 +994,8 @@ sub GetSetData { ## no critic 'complexity' $state = "ok - switched consumer $d to $op"; BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "GETTER:all" ], 1); BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "SETTER:none"], 1); - } else { + } + else { $state = "Error - couldn't switch consumer $d to $op"; } } @@ -1111,8 +1122,8 @@ sub _doLogin { Log3($name, 1, qq{$name - Credentials couldn't be retrieved successfully - make sure you've set it with "set $name credentials "}); $state = "Credentials couldn't be read"; $errstate = 1; - - } else { + } + else { my $usernameField = "ctl00\$ContentPlaceHolder1\$Logincontrol1\$txtUserName"; my $passwordField = "ctl00\$ContentPlaceHolder1\$Logincontrol1\$txtPassword"; my $mempasswd = "ctl00\$ContentPlaceHolder1\$Logincontrol1\$MemorizePassword"; @@ -1135,9 +1146,9 @@ sub _doLogin { if(__isLoggedIn ($name,$username,$loginp)) { # Login erfolgeich(Landing Pages können im Portal eingestellt werden!) handleCounter ($name, "dailyIssueCookieCounter"); # Cookie Ausstellungszähler setzen BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "loginState:successful", "oldlogintime:".(gettimeofday())[0] ], 1); - $errstate = 0; - - } else { + $errstate = 0; + } + else { Log3 ($name, 2, "$name - ERROR - Login into SMA-Portal failed !"); $state = "login failed"; BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "loginState:failed", "NULL" ], 1); @@ -1145,8 +1156,8 @@ sub _doLogin { } } } - - } elsif ($loginp->is_redirect) { + } + elsif ($loginp->is_redirect) { $retcode = $loginp->code; $location = $loginp->header('Location') // ""; Log3 ($name, 3, "$name - User is already logged in."); @@ -1158,8 +1169,8 @@ sub _doLogin { BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "loginState:successful", "NULL" ], 1); $errstate = 0; - - } else { + } + else { $errstate = 1; $state = $loginp->status_line; BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "loginState:failed", "NULL" ], 1); @@ -1508,19 +1519,20 @@ return ($errstate,$state,$reread,$retry); # (anchorTime beachten !) ################################################################ sub _getBalanceDayData { ## no critic "not used" - my $paref = shift; - my $name = $paref->{name}; - my $ua = $paref->{ua}; # LWP Useragent - my $state = $paref->{state}; - my $daref = $paref->{daref}; # Referenz zum Datenarray + my $paref = shift; + my $name = $paref->{name}; + my $ua = $paref->{ua}; # LWP Useragent + my $state = $paref->{state}; + my $daref = $paref->{daref}; # Referenz zum Datenarray my ($reread,$retry,$errstate) = (0,0,0); - my @bd = split /\s+/x ,AttrVal($name, "balanceDay", "current"); + my @bd = split /\s+/x ,AttrVal($name, "balanceDay", "current"); + my $tag = "balanceDayData"; for my $bal (@bd) { my ($y,$m,$d); - my $addon = "Day"; + my $addon = "Day_"; if($bal !~ /current/ixms) { ($y,$m,$d) = $bal =~ /(\d{4})-(\d{2})-(\d{2})/x; @@ -1530,7 +1542,7 @@ sub _getBalanceDayData { ## no critic "not used" next; } - $addon .= "_".$bal; + $addon .= $bal; $y -= 1900; $m -= 1; } @@ -1539,9 +1551,17 @@ sub _getBalanceDayData { ## no critic "not used" my $time = time - ($mp * 86400); (undef,undef,undef,$d,$m,$y) = localtime($time); - $addon .= "_".($y+1900)."-".sprintf("%02d",($m+1))."-".sprintf("%02d",$d); + my $addon1 = ($y+1900)."-".(sprintf "%02d", $m+1)."-".sprintf "%02d",$d; - Log3 ($name, 4, qq{$name - retrieve relative balanceDayData "$addon"}); + my $params = { + name => $name, + bal => $bal, + tag => $tag, + daref => $daref, + addon => $addon, + addon1 => $addon1, + }; + $addon = createDateAddon ($params); } eval { timelocal(0, 0, 0, $d, $m, $y) } or do { $state = (split(" at", $@))[0]; @@ -1549,10 +1569,12 @@ sub _getBalanceDayData { ## no critic "not used" Log3($name, 2, "$name - ERROR - invalid date/time format in attribute 'balanceDay' detected: $state"); return ($errstate,$state,$reread,$retry); }; + + Log3 ($name, 4, "$name - retrieve $tag ".($y+1900)."-".(sprintf "%02d", $m+1)."-".sprintf "%02d",$d ); - my $cts = fhemTimeLocal(0, 0, 0, $d, $m, $y); - my $offset = fhemTzOffset($cts); - my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum + my $cts = fhemTimeLocal(0, 0, 0, $d, $m, $y); + my $offset = fhemTzOffset($cts); + my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum my $tab = 1; # Tab 1 -> Tag , 2->Monat, 3->Jahr, 4->Gesamt my %fields = ("Content-Type" => "application/json; charset=utf-8"); @@ -1561,15 +1583,14 @@ sub _getBalanceDayData { ## no critic "not used" ($errstate,$state) = __dispatchPost ({ name => $name, ua => $ua, call => 'https://www.sunnyportal.com/FixedPages/HoManEnergyRedesign.aspx/GetLegendWithValues', - tag => "balanceDayData", + tag => $tag, state => $state, fnaref => [ qw( extractStatisticData ) ], fields => \%fields, content => $cont, addon => $addon, daref => $daref - }); - + }); } return ($errstate,$state,$reread,$retry); @@ -1580,19 +1601,20 @@ return ($errstate,$state,$reread,$retry); # (anchorTime beachten !) ################################################################ sub _getBalanceMonthData { ## no critic "not used" - my $paref = shift; - my $name = $paref->{name}; - my $ua = $paref->{ua}; # LWP Useragent - my $state = $paref->{state}; - my $daref = $paref->{daref}; # Referenz zum Datenarray + my $paref = shift; + my $name = $paref->{name}; + my $ua = $paref->{ua}; # LWP Useragent + my $state = $paref->{state}; + my $daref = $paref->{daref}; # Referenz zum Datenarray my ($reread,$retry,$errstate) = (0,0,0); - my @bd = split /\s+/x ,AttrVal($name, "balanceMonth", "current"); + my @bd = split /\s+/x ,AttrVal($name, "balanceMonth", "current"); + my $tag = "balanceMonthData"; for my $bal (@bd) { my ($y,$m); - my $addon = "Month"; + my $addon = "Month_"; if($bal !~ /current/ixms) { ($y,$m) = $bal =~ /^(\d{4})-(\d{2})$/x; @@ -1602,7 +1624,7 @@ sub _getBalanceMonthData { ## no critic "not used" next; } - $addon .= "_".$bal; + $addon .= $bal; $y -= 1900; $m -= 1; } @@ -1611,9 +1633,9 @@ sub _getBalanceMonthData { ## no critic "not used" my $yc = int($mp/12); # Anzahl der Jahre my $mc = $mp % 12; # Anzahl Restmonate - $y = (localtime(time))[5]; - $y -= $yc; - $m = (localtime(time))[4]; + $y = (localtime(time))[5]; + $y -= $yc; + $m = (localtime(time))[4]; if($m-$mc < 1) { $m = 12-abs($m-$mc); @@ -1623,9 +1645,17 @@ sub _getBalanceMonthData { ## no critic "not used" $m = $m-$mc; } - $addon .= "_".($y+1900)."-".sprintf("%02d",($m+1)); + my $addon1 = ($y+1900)."-".sprintf "%02d", $m+1; - Log3 ($name, 4, qq{$name - retrieve relative balanceMonthData "$addon"}); + my $params = { + name => $name, + bal => $bal, + tag => $tag, + daref => $daref, + addon => $addon, + addon1 => $addon1, + }; + $addon = createDateAddon ($params); } eval { timelocal(0, 0, 0, 1, $m, $y) } or do { $state = (split(" at", $@))[0]; @@ -1634,9 +1664,11 @@ sub _getBalanceMonthData { ## no critic "not used" return ($errstate,$state,$reread,$retry); }; - my $cts = fhemTimeLocal(0, 0, 0, 1, $m, $y); - my $offset = fhemTzOffset($cts); - my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum + Log3 ($name, 4, "$name - retrieve $tag ".($y+1900)."-".sprintf "%02d", $m+1); + + my $cts = fhemTimeLocal(0, 0, 0, 1, $m, $y); + my $offset = fhemTzOffset($cts); + my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum my $tab = 2; # Tab 1 -> Tag , 2->Monat, 3->Jahr, 4->Gesamt my %fields = ("Content-Type" => "application/json; charset=utf-8"); @@ -1645,15 +1677,14 @@ sub _getBalanceMonthData { ## no critic "not used" ($errstate,$state) = __dispatchPost ({ name => $name, ua => $ua, call => 'https://www.sunnyportal.com/FixedPages/HoManEnergyRedesign.aspx/GetLegendWithValues', - tag => "balanceMonthData", + tag => $tag, state => $state, fnaref => [ qw( extractStatisticData ) ], fields => \%fields, content => $cont, addon => $addon, daref => $daref - }); - + }); } return ($errstate,$state,$reread,$retry); @@ -1664,19 +1695,20 @@ return ($errstate,$state,$reread,$retry); # (anchorTime beachten !) ################################################################ sub _getBalanceYearData { ## no critic "not used" - my $paref = shift; - my $name = $paref->{name}; - my $ua = $paref->{ua}; # LWP Useragent - my $state = $paref->{state}; - my $daref = $paref->{daref}; # Referenz zum Datenarray + my $paref = shift; + my $name = $paref->{name}; + my $ua = $paref->{ua}; # LWP Useragent + my $state = $paref->{state}; + my $daref = $paref->{daref}; # Referenz zum Datenarray my ($reread,$retry,$errstate) = (0,0,0); - my @bd = split /\s+/x ,AttrVal($name, "balanceYear", "current"); + my @bd = split /\s+/x ,AttrVal($name, "balanceYear", "current"); + my $tag = "balanceYearData"; for my $bal (@bd) { my $y; - my $addon = "Year"; + my $addon = "Year_"; if($bal !~ /current/ixms) { ($y) = $bal =~ /^(\d{4})$/x; @@ -1686,16 +1718,24 @@ sub _getBalanceYearData { ## no critic "not used" next; } - $addon .= "_".$bal; + $addon .= $bal; $y -= 1900; } else { - my $mp = (split "-", $bal)[1] // 0; - $y = (localtime(time))[5]; - $y -= $mp; - $addon .= "_".($y+1900); + my $mp = (split "-", $bal)[1] // 0; + $y = (localtime(time))[5]; + $y -= $mp; + my $addon1 = $y+1900; - Log3 ($name, 4, qq{$name - retrieve relative balanceYearData "$addon"}); + my $params = { + name => $name, + bal => $bal, + tag => $tag, + daref => $daref, + addon => $addon, + addon1 => $addon1, + }; + $addon = createDateAddon ($params); } eval { timelocal(0, 0, 0, 1, 1, $y) } or do { $state = (split(" at", $@))[0]; @@ -1703,10 +1743,12 @@ sub _getBalanceYearData { ## no critic "not used" Log3($name, 2, "$name - ERROR - invalid date/time format in attribute 'balanceYear' detected: $state"); return ($errstate,$state,$reread,$retry); }; + + Log3 ($name, 4, "$name - retrieve $tag ".($y+1900)); - my $cts = fhemTimeLocal(0, 0, 0, 1, 1, $y); - my $offset = fhemTzOffset($cts); - my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum + my $cts = fhemTimeLocal(0, 0, 0, 1, 1, $y); + my $offset = fhemTzOffset($cts); + my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum my $tab = 3; # Tab 1 -> Tag , 2->Monat, 3->Jahr, 4->Gesamt my %fields = ("Content-Type" => "application/json; charset=utf-8"); @@ -1715,7 +1757,7 @@ sub _getBalanceYearData { ## no critic "not used" ($errstate,$state) = __dispatchPost ({ name => $name, ua => $ua, call => 'https://www.sunnyportal.com/FixedPages/HoManEnergyRedesign.aspx/GetLegendWithValues', - tag => "balanceYearData", + tag => $tag, state => $state, fnaref => [ qw( extractStatisticData ) ], fields => \%fields, @@ -2057,8 +2099,8 @@ sub ___analyzeData { ## no critic 'complexity' } } } - - } else { + } + else { my $njdat = encode("utf8", $ad->as_string); if($njdat =~ /401\s-\sUnauthorized/x) { @@ -2517,7 +2559,7 @@ sub extractStatisticData { my $name = $hash->{NAME}; my $sd; - Log3 ($name, 4, "$name - ##### extracting balance data #### "); + Log3 ($name, 4, "$name - extracting balance data "); $statistic = eval{decode_json($statistic)} or do { Log3 ($name, 2, "$name - ERROR - can't decode JSON Data"); return; @@ -2569,7 +2611,8 @@ sub extractPlantMasterData { Log3 ($name, 4, "$name - Plant ID: ".$plantOid); $hash->{HELPER}{PLANTOID} = $plantOid; BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "PLANTOID:$plantOid"], 1); - } else { + } + else { Log3 ($name, 4, "$name - Plant ID not set !"); } @@ -2695,16 +2738,20 @@ sub extractConsumerPlanData { my $rb = "${lv}_${cn}_PlannedOpTimeBegin"; my $re = "${lv}_${cn}_PlannedOpTimeEnd"; my $rp = "${lv}_${cn}_Planned"; + if($pos) { push @$daref, "$rb:$pos"; push @$daref, "$rp:yes"; - } else { + } + else { push @$daref, "$rb:undefined"; push @$daref, "$rp:no"; } + if($poe) { push @$daref, "$re:$poe"; - } else { + } + else { push @$daref, "$re:undefined"; } } @@ -2814,11 +2861,14 @@ sub extractConsumerCurrentdata { if(!$GriSwStt && $GriSwAuto) { $res = "off (automatic)"; - } elsif (!$GriSwStt && !$GriSwAuto) { + } + elsif (!$GriSwStt && !$GriSwAuto) { $res = "off"; - } elsif ($GriSwStt) { + } + elsif ($GriSwStt) { $res = "on"; - } else { + } + else { $res = "undefined"; } @@ -2943,7 +2993,8 @@ sub setVersionInfo { $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: 76_SMAPortal.pm 22640 2020-08-21 07:30:21Z DS_Starter $ im Kopf komplett! vorhanden ) $modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx; - } else { + } + else { $modules{$type}{META}{x_version} = $v; } return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 76_SMAPortal.pm 22640 2020-08-21 07:30:21Z DS_Starter $ im Kopf komplett! vorhanden ) @@ -2952,7 +3003,8 @@ sub setVersionInfo { # mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); ## no critic 'VERSION' } - } else { + } + else { # herkömmliche Modulstruktur $hash->{VERSION} = $v; } @@ -3024,6 +3076,31 @@ sub deleteData { return; } +################################################################ +# erstelle addon als relative oder reale Datumangabe +################################################################ +sub createDateAddon { + my $paref = shift; + my $name = $paref->{name}; + my $bal = $paref->{bal}; + my $tag = $paref->{tag}; + my $daref = $paref->{daref}; + my $addon = $paref->{addon}; + my $addon1 = $paref->{addon1}; + + if(AttrVal($name,"useRelativeNames", 0)) { # current-x verwenden statt effektives Datum + $addon .= $bal; + my $lv = $stpl{$tag}{level}; + + push @$daref, "${lv}_${addon}_Date:$addon1"; + } + else { + $addon .= $addon1; + } + +return $addon; +} + ################################################################ # statistische Counter managen # $name = Name Device @@ -3067,11 +3144,14 @@ sub setFromBlocking { if($helper ne "NULL") { my ($hnam,$k1,$k2,$k3) = split ":", $helper, 4; + if(defined $k3) { $hash->{HELPER}{"$hnam"}{"$k1"}{"$k2"} = $k3; - } elsif (defined $k2) { + } + elsif (defined $k2) { $hash->{HELPER}{"$hnam"}{"$k1"} = $k2; - } else { + } + else { $hash->{HELPER}{"$hnam"} = $k1; } } @@ -3113,7 +3193,8 @@ sub TimeAdjust { if(lc($tkind) =~ /unspecified/x) { if($isdst) { $epoch = $epoch - 7200; - } else { + } + else { $epoch = $epoch - 3600; } } @@ -3125,7 +3206,8 @@ sub TimeAdjust { if(AttrVal("global","language","EN") eq "DE") { return (sprintf("%02d.%02d.%04d %02d:%s", $lday,$lmonth,$lyear,$lhour,$rest)); - } else { + } + else { return (sprintf("%04d-%02d-%02d %02d:%s", $lyear,$lmonth,$lday,$lhour,$rest)); } } @@ -3185,13 +3267,17 @@ sub PortalAsHtml { $ret .= ""; if(!$hash) { ## no critic "Cascading" $ret .= "Device \"$name\" doesn't exist !"; - } elsif (!defined($defs{$wlname})) { + } + elsif (!defined($defs{$wlname})) { $ret .= "Graphic device \"$wlname\" doesn't exist !"; - } elsif (!$fdo) { + } + elsif (!$fdo) { $ret .= qq{The attribute "providerLevel" of device "$name" must contain the level "forecastData" and data must be retrieved !}; - } elsif (!defined $pv0) { + } + elsif (!defined $pv0) { $ret .= "Awaiting minor level forecast data ..."; - } elsif (!defined $pv1) { + } + elsif (!defined $pv1) { $ret .= "Awaiting major level forecast data ..."; } @@ -3224,18 +3310,21 @@ sub PortalAsHtml { my $swicon = ""; if($swstate eq "off") { $swicon = ""; - } elsif ($swstate eq "on") { + } + elsif ($swstate eq "on") { $swicon = ""; - } elsif ($swstate =~ /off.*automatic.*/ix) { + } + elsif ($swstate =~ /off.*automatic.*/ix) { $swicon = ""; } if ($legend_style eq 'icon') { # mögliche Umbruchstellen mit normalen Blanks vorsehen ! $legend_txt .= $txt.' '.FW_makeImage($im).' '.$swicon.'  '; - } else { + } + else { my (undef,$co) = split('\@',$im); - $co = '#cccccc' if (!$co); # Farbe per default - $legend_txt .= ''.$txt.' '.$swicon.'  '; # hier auch Umbruch erlauben + $co = '#cccccc' if (!$co); # Farbe per default + $legend_txt .= ''.$txt.' '.$swicon.'  '; # hier auch Umbruch erlauben } } } @@ -3291,7 +3380,8 @@ sub PortalAsHtml { $pvRe = sprintf("%.1f" , $pvRe/1000)." kWh"; $pvTo = sprintf("%.1f" , $pvTo/1000)." kWh"; $pvCu = sprintf("%.1f" , $pvCu/1000)." kW"; - } else { + } + else { $co4h .= " Wh"; $coRe .= " Wh"; $coTo .= " Wh"; @@ -3332,7 +3422,8 @@ sub PortalAsHtml { if(AttrVal("global","language","EN") eq "DE") { $lup = "$day.$month.$year $time"; - } else { + } + else { $lup = "$year-$month-$day $time"; } @@ -3347,9 +3438,11 @@ sub PortalAsHtml { if ($upstate =~ /ok/ix) { $upicon = ""; - } elsif ($upstate =~ /running/ix) { + } + elsif ($upstate =~ /running/ix) { $upicon = ""; - } else { + } + else { $upicon = ""; } @@ -3391,7 +3484,8 @@ sub PortalAsHtml { if(AttrVal("global","language","EN") eq "DE") { (undef,undef,undef,$t{0}) = ReadingsVal($name,"${fmin}_ThisHour_Time",'0') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x; - } else { + } + else { (undef,undef,undef,$t{0}) = ReadingsVal($name,"${fmin}_ThisHour_Time",'0') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x; } @@ -3412,7 +3506,8 @@ sub PortalAsHtml { if(AttrVal("global","language","EN") eq "DE") { (undef,undef,undef,$start) = ReadingsVal($name,"${fmaj}_".$itemName."_PlannedOpTimeBegin",'00.00.0000 24') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x; (undef,undef,undef,$end) = ReadingsVal($name,"${fmaj}_".$itemName."_PlannedOpTimeEnd",'00.00.0000 24') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x; - } else { + } + else { (undef,undef,undef,$start) = ReadingsVal($name,"${fmaj}_".$itemName."_PlannedOpTimeBegin",'0000-00-00 24') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x; (undef,undef,undef,$end) = ReadingsVal($name,"${fmaj}_".$itemName."_PlannedOpTimeEnd",'0000-00-00 24') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x; } @@ -3425,19 +3520,21 @@ sub PortalAsHtml { if ($start < $t{0}) { # consumption seems to be tomorrow $start = 24-$t{0}+$start; $flag = 1; - } else { + } + else { $start -= $t{0}; } if ($flag) { # consumption seems to be tomorrow $end = 24-$t{0}+$end; - } else { + } + else { $end -= $t{0}; } $_ .= ":".$start.":".$end; - - } else { + } + else { $_ .= ":24:24"; } Log3($name, 4, "$name - Consumer planned data: $_"); @@ -3464,7 +3561,8 @@ sub PortalAsHtml { if(AttrVal("global","language","EN") eq "DE") { (undef,undef,undef,$t{$i}) = ReadingsVal($name,"${fmaj}_NextHour".sprintf("%02d",$i)."_Time",'0') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x; - } else { + } + else { (undef,undef,undef,$t{$i}) = ReadingsVal($name,"${fmaj}_NextHour".sprintf("%02d",$i)."_Time",'0') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x; } @@ -3511,7 +3609,8 @@ sub PortalAsHtml { $val ='???' if ($val eq $icon_name); # passendes Icon beim User nicht vorhanden ! ( attr web iconPath falsch/prüfen/update ? ) $ret .= "$val"; - } else { # Kein Ertrag oder show_night = 0 + } + else { # Kein Ertrag oder show_night = 0 $ret .= ""; $we{$i} = undef; } # mit $we{$i} = undef kann man unten leicht feststellen ob für diese Spalte bereits ein Icon ausgegeben wurde oder nicht @@ -3545,12 +3644,12 @@ sub PortalAsHtml { if ($type eq 'co') { $he = int(($maxCon-$co{$i})/$maxCon*$height) + $fsize; # he - freier der Raum über den Balken. $z3 = int($height + $fsize - $he); # Resthöhe - - } elsif ($type eq 'pv') { + } + elsif ($type eq 'pv') { $he = int(($maxVal-$pv{$i})/$maxVal*$height) + $fsize; $z3 = int($height + $fsize - $he); - - } elsif ($type eq 'pvco') { + } + elsif ($type eq 'pvco') { # Berechnung der Zonen # he - freier der Raum über den Balken. fsize wird nicht verwendet, da bei diesem Typ keine Zahlen über den Balken stehen # z2 - der Ertrag ggf mit Icon @@ -3561,7 +3660,8 @@ sub PortalAsHtml { if ($pv{$i} > $co{$i}) { # pv oben , co unten $z2 = $pv{$i}; $z3 = $co{$i}; - } else { # tauschen, Verbrauch ist größer als Ertrag + } + else { # tauschen, Verbrauch ist größer als Ertrag $z3 = $pv{$i}; $z2 = $co{$i}; } @@ -3572,9 +3672,9 @@ sub PortalAsHtml { if ($z3 < int($fsize/2)) { # dünnen Strichbalken vermeiden / ca. halbe Zeichenhöhe $z2 += $z3; $z3 = 0; - } - - } else { # Typ dif + } + } + else { # Typ dif # Berechnung der Zonen # he - freier der Raum über den Balken , Zahl positiver Wert + fsize # z2 - positiver Balken inkl Icon @@ -3587,16 +3687,18 @@ sub PortalAsHtml { if ($maxPV) { # Feste Aufteilung +/- , jeder 50 % bei maxPV = 0 $px_pos = int($height/2); $px_neg = $height - $px_pos; # Rundungsfehler vermeiden - - } else { # Dynamische hoch/runter Verschiebung der Null-Linie + } + else { # Dynamische hoch/runter Verschiebung der Null-Linie if ($minDif >= 0 ) { # keine negativen Balken vorhanden, die Positiven bekommen den gesammten Raum $px_neg = 0; $px_pos = $height; - } else { + } + else { if ($maxDif > 0) { $px_neg = int($height * abs($minDif) / ($maxDif + abs($minDif))); # Wieviel % entfallen auf unten ? $px_pos = $height-$px_neg; # der Rest ist oben - } else { # keine positiven Balken vorhanden, die Negativen bekommen den gesammten Raum + } + else { # keine positiven Balken vorhanden, die Negativen bekommen den gesammten Raum $px_neg = $height; $px_pos = 0; } @@ -3606,7 +3708,8 @@ sub PortalAsHtml { if ($di{$i} >= 0) { # Zone 2 & 3 mit ihren direkten Werten vorbesetzen $z2 = $di{$i}; $z3 = abs($minDif); - } else { + } + else { $z2 = $maxDif; $z3 = abs($di{$i}); # Nur Betrag ohne Vorzeichen } @@ -3654,9 +3757,9 @@ sub PortalAsHtml { $ret .= consinject($hash,$i,@pgCDev) if($ret); $ret .= ""; - } - - } elsif ($type eq 'pvco') { + } + } + elsif ($type eq 'pvco') { my ($color1, $color2, $style1, $style2); $ret .="\n"; # mit width=100% etwas bessere Füllung der Balken @@ -3675,8 +3778,7 @@ sub PortalAsHtml { $color2 = $colorc; $style2 = "style=\"padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;"; $style2 .= (defined($color2)) ? " background-color:#$color2\"" : '"'; - } - + } } else { $val = formatVal6($co{$i},$kw,$we{$i}); $color1 = $colorc; @@ -3705,8 +3807,8 @@ sub PortalAsHtml { $ret .= ""; $ret .= ""; } - - } else { # Type dif + } + else { # Type dif my $style = "style=\"padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;"; $ret .="
$v
\n"; # Tipp : das nachfolgende border=0 auf 1 setzen hilft sehr Ausgabefehler zu endecken @@ -3726,8 +3828,8 @@ sub PortalAsHtml { $ret .= ""; - - } else { # ohne Farbe + } + else { # ohne Farbe $z2 = 2 if ($di{$i} == 0); # Sonderfall, hier wird die 0 gebraucht ! if ($z2 && $val) { # z2 weglassen wenn nicht unbedigt nötig bzw. wenn zuvor he mit val keinen Wert hatte $ret .= ""; @@ -3739,8 +3841,8 @@ sub PortalAsHtml { $style .= (defined($colorc)) ? " background-color:#$colorc\"" : '"'; # mit Farbe 2 colorc füllen $ret .= ""; $ret .= ""; - - } elsif ($z3) { # ohne Farbe + } + elsif ($z3) { # ohne Farbe $ret .=""; $ret .=""; } @@ -3833,15 +3935,19 @@ sub formatVal6 { if (!$t) { # glatte Zahl ohne Nachkommastelle if(!$v) { return ' '; # 0 nicht anzeigen, passt eigentlich immer bis auf einen Fall im Typ diff - } elsif ($v < 10) { + } + elsif ($v < 10) { return '  '.$n.$v.'  '; - } else { + } + else { return '  '.$n.$v.' '; } - } else { # mit Nachkommastelle -> zwei Zeichen mehr .X + } + else { # mit Nachkommastelle -> zwei Zeichen mehr .X if ($v < 10) { return ' '.$n.$v.' '; - } else { + } + else { return $n.$v.' '; } } @@ -3931,7 +4037,8 @@ sub SPGRefresh { if (ref $hash ne "HASH") { ($name,$pload,$lpollspg) = split ",",$hash; $hash = $defs{$name}; - } else { + } + else { $name = $hash->{NAME}; } my $fpr = 0; @@ -3951,11 +4058,13 @@ sub SPGRefresh { my $room = $_; { map { FW_directNotify("FILTER=room=$room", "#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context'; } - } elsif ($pload && (!$hash->{HELPER}{SPGROOM} || $hash->{HELPER}{SPGDETAIL})) { + } + elsif ($pload && (!$hash->{HELPER}{SPGROOM} || $hash->{HELPER}{SPGDETAIL})) { # trifft zu bei Detailansicht oder im FLOORPLAN bzw. Dashboard oder wenn Seitenrefresh mit dem # SMAPortalSPG-Attribut "forcePageRefresh" erzwungen wird { map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context'; - } else { + } + else { if($fpr) { { map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context'; } @@ -4287,6 +4396,13 @@ return; attr <name> userAgent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0

+ + +
  • useRelativeNames
    + When using relative dates current-x (see balance.* attributes) the created reading name contains + also the relative instead of the real date.
    + (default: real date) +

  • verbose5Data
    @@ -4613,6 +4729,13 @@ return;

  • + + +
  • useRelativeNames
    + Bei Verwendung von relativen Datumangaben current-x (siehe balance.*-Attribute) enthält der erstellte Readingname + ebenfalls die relative anstatt der realen Datumangabe.
    + (default: reale Datumangabe) +

  • verbose5Data
  • "; $ret .= $is{$i} if (defined $is{$i}); $ret .="