diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm index 082a42282..1d0e7fd8b 100644 --- a/fhem/FHEM/76_SolarForecast.pm +++ b/fhem/FHEM/76_SolarForecast.pm @@ -156,6 +156,7 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "1.37.2" => "24.10.2024 _flowGraphic: show Producer Row only if more than one Producer is defined ", "1.37.1" => "23.10.2024 state: 'The setup routine is still incomplete' if setup is incomplete ". "change: 'trackFlex' && \$wcc >= 80 to \$wcc >= 70, implement Rename function ". "_flowGraphic: eliminate numbers in device name - Forum: https://forum.fhem.de/index.php?msg=1323229 ", @@ -14282,11 +14283,14 @@ sub _flowGraphic { ##################################### my ($togrid, $tonode, $tobat) = __sortProducer ($pdcr); # lfn Producer sortiert nach ptyp und feed - my $psorted = { + my $psorted = { '1togrid' => { xicon => -100, xchain => 350, ychain => 420, step => 70, count => scalar @{$togrid}, sorted => $togrid }, # Producer/PV nur zu Grid '2tonode' => { xicon => 350, xchain => 700, ychain => 200, step => $pdist, count => scalar @{$tonode}, sorted => $tonode }, # Producer/PV zum Knoten '3tobat' => { xicon => 750, xchain => 1100, ychain => 430, step => 40, count => scalar @{$tobat}, sorted => $tobat }, # Producer/PV nur zu Batterie }; + + my $doproducerrow = 1; + $doproducerrow = 0 if(!$psorted->{'1togrid'}{count} && !$psorted->{'3tobat'}{count} && $psorted->{'2tonode'}{count} == 1); ## definierte Verbraucher ermitteln ##################################### @@ -14356,13 +14360,13 @@ sub _flowGraphic { ######################################### my $vbwidth = 800; # width and height specify the viewBox size my $vbminx = -10 * $flowgshift; # min-x and min-y represent the smallest X and Y coordinates that the viewBox may have - my $vbminy = -25; + my $vbminy = $doproducerrow ? -25 : 125; # Grafik höher positionieren wenn keine Poducerreihe angezeigt my $vbhight = !$flowgcons ? 380 : !$flowgconsTime ? 590 : 610; - $vbhight += 100; + if ($doproducerrow) {$vbhight += 100}; # Höhe Box vergrößern wenn Poducerreihe angezeigt my $vbox = "$vbminx $vbminy $vbwidth $vbhight"; my $svgstyle = 'width:98%; height:'.$flowgsize.'px;'; @@ -14402,61 +14406,32 @@ END0 ## Producer Icon - in Reihenfolge: zum Grid - zum Knoten - zur Batterie ######################################################################### - for my $st (sort keys %{$psorted}) { - my $left = 0; - my $xicon = $psorted->{$st}{xicon}; - my $count = $psorted->{$st}{count}; - my @sorted = @{$psorted->{$st}{sorted}}; + $paref->{stna} = $stna; + $paref->{pnodesum} = $pnodesum; + $paref->{psorted} = $psorted; + $paref->{pdcr} = $pdcr; + $paref->{pdist} = $pdist; + + if (!$doproducerrow) { + $paref->{y_coord} = 165; + $ret .= __addProducerIcon ($paref); # Producer Icons row einfügen + } + else { # mehr als ein Producer vorhanden + $paref->{y_coord} = 0; + $ret .= __addProducerIcon ($paref); # Producer Icons row einfügen - if ($count % 2) { - $xicon = $xicon - ($pdist * ($count - 1) / 2); - } - else { - $xicon = $xicon - ($pdist / 2 * ($count - 1)); - } - - $psorted->{$st}{start} = $xicon; - $left = $xicon + 5; - - for my $lfn (@sorted) { - my $pn = $pdcr->{$lfn}{pn}; - my ($picon, $ptxt) = __substituteIcon ( { hash => $hash, # Icon des Producerdevices - name => $name, - pn => $pn, - ptyp => $pdcr->{$lfn}{ptyp}, - don => NexthoursVal ($hash, 'NextHour00', 'DoN', 0), # Tag oder Nacht - pcurr => $pdcr->{$lfn}{p}, - lang => $lang - } - ); - - $picon = FW_makeImage ($picon, ''); - ($scale, $picon) = __normIconScale ($picon, $name); - - $ret .= qq{}; - $ret .= "$ptxt".$picon; - $ret .= ' '; - - $left += $pdist; - } + $paref->{x_coord} = 360; + $paref->{y_coord} = 165; + $ret .= __addNodeIcon ($paref); # Knoten Icon } - ## Knoten Icon - ################ - my ($nicon, $ntxt) = __substituteIcon ( { hash => $hash, - name => $name, - ptyp => 'node', - pcurr => $pnodesum, - lang => $lang - } - ); - - $nicon = FW_makeImage ($nicon, ''); - ($scale, $nicon) = __normIconScale ($nicon, $name); - - $ret .= qq{}; # translate(X-Koordinate,Y-Koordinate), scale()-> Koordinaten ändern sich bei Größenänderung - $ret .= "$ntxt".$nicon; - $ret .= ' '; + delete $paref->{stna}; + delete $paref->{pnodesum}; + delete $paref->{psorted}; + delete $paref->{pdcr}; + delete $paref->{pdist}; + delete $paref->{x_coord}; + delete $paref->{y_coord}; ## Consumer Liste und Icons in Grafik anzeigen ################################################ @@ -14578,37 +14553,40 @@ END3 } ## Producer Laufketten - in Reihenfolge: zum Grid - zum Knoten - zur Batterie + ## Laufkette nur anzeigen wenn Producerzeile angezeigt werden soll ############################################################################### - for my $st (sort keys %{$psorted}) { - my $left = $psorted->{$st}{start} * 2; # Übertrag aus Producer Icon Abschnitt - my $count = $psorted->{$st}{count}; - my $xchain = $psorted->{$st}{xchain}; # X- Koordinate Kette am Ziel - my $ychain = $psorted->{$st}{ychain}; # Y- Koordinate Kette am Ziel - my $step = $psorted->{$st}{step}; - my @sorted = @{$psorted->{$st}{sorted}}; + if ($doproducerrow) { + for my $st (sort keys %{$psorted}) { + my $left = $psorted->{$st}{start} * 2; # Übertrag aus Producer Icon Abschnitt + my $count = $psorted->{$st}{count}; + my $xchain = $psorted->{$st}{xchain}; # X- Koordinate Kette am Ziel + my $ychain = $psorted->{$st}{ychain}; # Y- Koordinate Kette am Ziel + my $step = $psorted->{$st}{step}; + my @sorted = @{$psorted->{$st}{sorted}}; - if ($count % 2) { - $xchain = $xchain - ($pdist * ($count -1) / 2); - } - else { - $xchain = $xchain - ($pdist / 2 * ($count - 1)); - } - - my $producer_style; - - for my $lfn (@sorted) { - my $pn = $pdcr->{$lfn}{pn}; - my $p = $pdcr->{$lfn}{p}; - $producer_style = $p > 0 ? "$stna active_normal" : "$stna inactive"; - my $chain_color = ''; # Farbe der Laufkette des Producers - - if ($p) { - #$chain_color = 'style="stroke: #'.substr(Color::pahColor(0,50,100,$p,[0,255,0, 127,255,0, 255,255,0, 255,127,0, 255,0,0]),0,6).';"'; + if ($count % 2) { + $xchain = $xchain - ($pdist * ($count -1) / 2); + } + else { + $xchain = $xchain - ($pdist / 2 * ($count - 1)); + } + + my $producer_style; + + for my $lfn (@sorted) { + my $pn = $pdcr->{$lfn}{pn}; + my $p = $pdcr->{$lfn}{p}; + $producer_style = $p > 0 ? "$stna active_normal" : "$stna inactive"; + my $chain_color = ''; # Farbe der Laufkette des Producers + + if ($p) { + #$chain_color = 'style="stroke: #'.substr(Color::pahColor(0,50,100,$p,[0,255,0, 127,255,0, 255,255,0, 255,127,0, 255,0,0]),0,6).';"'; + } + + $ret .= qq{}; + $left += ($pdist * 2); + $xchain += $step; } - - $ret .= qq{}; - $left += ($pdist * 2); - $xchain += $step; } } @@ -14666,35 +14644,38 @@ END3 $ret .= qq{$cc_dummy} if ($flowgconX && $flowgconsPower); # Current_Consumption Dummy ## Textangabe Producer - in Reihenfolge: zum Grid - zum Knoten - zur Batterie - ############################################################################### - for my $st (sort keys %{$psorted}) { - my $left = $psorted->{$st}{start} * 2 - 70; # Übertrag aus Producer Icon Abschnitt, -XX -> Start Lage Producer Beschriftung - my @sorted = @{$psorted->{$st}{sorted}}; - - for my $lfn (@sorted) { - my $pn = $pdcr->{$lfn}{pn}; - $currentPower = $pdcr->{$lfn}{p}; - $lcp = length $currentPower; - - # Leistungszahl abhängig von der Größe entsprechend auf der x-Achse verschieben - ############################################################################### - if ($lcp >= 5) {$left -= 10} - elsif ($lcp == 4) {$left += 10} - elsif ($lcp == 3) {$left += 15} - elsif ($lcp == 2) {$left += 20} - elsif ($lcp == 1) {$left += 40} - - $ret .= qq{$currentPower} if($flowgPrdsPower); - - # Leistungszahl wieder zurück an den Ursprungspunkt - #################################################### - if ($lcp >= 5) {$left += 10} - elsif ($lcp == 4) {$left -= 10} - elsif ($lcp == 3) {$left -= 15} - elsif ($lcp == 2) {$left -= 20} - elsif ($lcp == 1) {$left -= 40} + ## Textangabe nur anzeigen wenn Producerzeile angezeigt werden soll + ############################################################################### + if ($doproducerrow) { + for my $st (sort keys %{$psorted}) { + my $left = $psorted->{$st}{start} * 2 - 70; # Übertrag aus Producer Icon Abschnitt, -XX -> Start Lage Producer Beschriftung + my @sorted = @{$psorted->{$st}{sorted}}; - $left += ($pdist * 2); + for my $lfn (@sorted) { + my $pn = $pdcr->{$lfn}{pn}; + $currentPower = $pdcr->{$lfn}{p}; + $lcp = length $currentPower; + + # Leistungszahl abhängig von der Größe entsprechend auf der x-Achse verschieben + ############################################################################### + if ($lcp >= 5) {$left -= 10} + elsif ($lcp == 4) {$left += 10} + elsif ($lcp == 3) {$left += 15} + elsif ($lcp == 2) {$left += 20} + elsif ($lcp == 1) {$left += 40} + + $ret .= qq{$currentPower} if($flowgPrdsPower); + + # Leistungszahl wieder zurück an den Ursprungspunkt + #################################################### + if ($lcp >= 5) {$left += 10} + elsif ($lcp == 4) {$left -= 10} + elsif ($lcp == 3) {$left -= 15} + elsif ($lcp == 2) {$left -= 20} + elsif ($lcp == 1) {$left -= 40} + + $left += ($pdist * 2); + } } } @@ -14783,6 +14764,97 @@ sub __sortProducer { return (\@togrid, \@tonode, \@tobat); } +################################################################ +# Producer Icon einfügen +################################################################ +sub __addProducerIcon { + my $paref = shift; + my $hash = $paref->{hash}; + my $name = $paref->{name}; + my $lang = $paref->{lang}; + my $stna = $paref->{stna}; + my $psorted = $paref->{psorted}; + my $pdcr = $paref->{pdcr}; + my $pdist = $paref->{pdist}; + my $y_coord = $paref->{y_coord}; + + my ($scale, $ret); + + for my $st (sort keys %{$psorted}) { + my $left = 0; + my $xicon = $psorted->{$st}{xicon}; + my $count = $psorted->{$st}{count}; + my @sorted = @{$psorted->{$st}{sorted}}; + + if ($count % 2) { + $xicon = $xicon - ($pdist * ($count - 1) / 2); + } + else { + $xicon = $xicon - ($pdist / 2 * ($count - 1)); + } + + $psorted->{$st}{start} = $xicon; + $left = $xicon + 5; + + for my $lfn (@sorted) { + my $pn = $pdcr->{$lfn}{pn}; + my ($picon, $ptxt) = __substituteIcon ( { hash => $hash, # Icon des Producerdevices + name => $name, + pn => $pn, + ptyp => $pdcr->{$lfn}{ptyp}, + don => NexthoursVal ($hash, 'NextHour00', 'DoN', 0), # Tag oder Nacht + pcurr => $pdcr->{$lfn}{p}, + lang => $lang + } + ); + + $picon = FW_makeImage ($picon, ''); + ($scale, $picon) = __normIconScale ($picon, $name); + + $ret .= qq{}; + $ret .= "$ptxt".$picon; + $ret .= ' '; + + $left += $pdist; + } + } + +return $ret; +} + +################################################################ +# Knoten Icon einfügen +################################################################ +sub __addNodeIcon { + my $paref = shift; + my $hash = $paref->{hash}; + my $name = $paref->{name}; + my $lang = $paref->{lang}; + my $stna = $paref->{stna}; + my $pnodesum = $paref->{pnodesum}; + my $x_coord = $paref->{x_coord}; + my $y_coord = $paref->{y_coord}; + + my $scale; + + my ($nicon, $ntxt) = __substituteIcon ( { hash => $hash, + name => $name, + ptyp => 'node', + pcurr => $pnodesum, + lang => $lang + } + ); + + $nicon = FW_makeImage ($nicon, ''); + ($scale, $nicon) = __normIconScale ($nicon, $name); + + my $ret = qq{}; # translate(X-Koordinate,Y-Koordinate), scale()-> Koordinaten ändern sich bei Größenänderung + $ret .= "$ntxt".$nicon; + $ret .= ' '; + +return $ret; +} + ################################################################ # prüfe ob Icon + Farbe angegeben ist # und setze ggf. Ersatzwerte