mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
76_SolarForecast.pm: contrib 0.56.0
git-svn-id: https://svn.fhem.de/fhem/trunk@24950 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
0786cc0367
commit
8d20c83965
@ -120,6 +120,7 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"0.56.0" => "11.09.2021 new Attr flowGraphicShowConsumer, extend calc consumer power consumption ",
|
||||
"0.55.3" => "08.09.2021 add powerthreshold to etotal key ",
|
||||
"0.55.2" => "08.09.2021 minor fixes, use Color ",
|
||||
"0.55.1" => "05.09.2021 delete invalid consumer index, Forum: https://forum.fhem.de/index.php/topic,117864.msg1173219.html#msg1173219 ",
|
||||
@ -507,9 +508,10 @@ my $defcmode = "can";
|
||||
my $caicondef = 'light_light_dim_100@gold'; # default consumerAdviceIcon
|
||||
|
||||
my $defflowGSize = 300; # default flowGraphicSize
|
||||
my $defpopercent = 0.5; # Standard % aktuelle Leistung an nominaler Leistung gemäß Typenschild
|
||||
|
||||
# Default CSS-Style
|
||||
my $cssdef = qq{.flowg.text { stroke: none; fill: gray; } \n}.
|
||||
my $cssdef = qq{.flowg.text { stroke: none; fill: gray; font-size: 32px;} \n}.
|
||||
qq{.flowg.sun_active { stroke: orange; fill: orange; } \n}.
|
||||
qq{.flowg.sun_inactive { stroke: gray; fill: gray; } \n}.
|
||||
qq{.flowg.bat25 { stroke: red; fill: red; } \n}.
|
||||
@ -583,6 +585,7 @@ sub Initialize {
|
||||
"disable:1,0 ".
|
||||
"flowGraphicSize ".
|
||||
"flowGraphicAnimate:1,0 ".
|
||||
"flowGraphicShowConsumer:1,0 ".
|
||||
"follow70percentRule:1,dynamic,0 ".
|
||||
"forcePageRefresh:1,0 ".
|
||||
"graphicSelect:both,flow,forecast,none ".
|
||||
@ -2167,6 +2170,10 @@ sub _specialActivities {
|
||||
deleteConsumerPlanning ($hash, $c);
|
||||
my $calias = ConsumerVal ($hash, $c, "alias", "");
|
||||
Log3 ($name, 3, qq{$name - Consumer planning of "$calias" deleted});
|
||||
|
||||
$data{$type}{$name}{consumers}{$c}{minutesOn} = 0;
|
||||
$data{$type}{$name}{consumers}{$c}{numberDayStarts} = 0;
|
||||
$data{$type}{$name}{consumers}{$c}{onoff} = "off";
|
||||
}
|
||||
|
||||
deleteReadingspec ($hash, "consumer.*_planned.*");
|
||||
@ -2602,6 +2609,7 @@ sub _manageConsumerData {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Zeit
|
||||
my $chour = $paref->{chour};
|
||||
my $day = $paref->{day};
|
||||
my $daref = $paref->{daref};
|
||||
@ -2609,19 +2617,44 @@ sub _manageConsumerData {
|
||||
my $nhour = $chour+1;
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
my $acref = $data{$type}{$name}{consumers};
|
||||
|
||||
for my $c (sort{$a<=>$b} keys %{$acref}) {
|
||||
my $consumer = $acref->{$c}{name};
|
||||
my $alias = $acref->{$c}{alias};
|
||||
for my $c (sort{$a<=>$b} keys %{$data{$type}{$name}{consumers}}) {
|
||||
my $consumer = ConsumerVal ($hash, $c, "name", "");
|
||||
my $alias = ConsumerVal ($hash, $c, "alias", "");
|
||||
|
||||
## aktuelle Leistung auslesen
|
||||
##############################
|
||||
my $paread = $acref->{$c}{rpcurr};
|
||||
my $up = $acref->{$c}{upcurr};
|
||||
my $paread = ConsumerVal ($hash, $c, "rpcurr", "");
|
||||
my $up = ConsumerVal ($hash, $c, "upcurr", "");
|
||||
my $pcurr = 0;
|
||||
|
||||
if($paread) {
|
||||
my $eup = $up =~ /^kW$/xi ? 1000 : 1;
|
||||
my $pcurr = ReadingsNum ($consumer, $paread, 0) * $eup;
|
||||
$pcurr = ReadingsNum ($consumer, $paread, 0) * $eup;
|
||||
|
||||
push @$daref, "consumer${c}_currentPower<>". $pcurr." W";
|
||||
}
|
||||
|
||||
## Verbrauch auslesen + speichern
|
||||
##################################
|
||||
my $pthreshold = 0;
|
||||
my $enread = ConsumerVal ($hash, $c, "retotal", "");
|
||||
my $u = ConsumerVal ($hash, $c, "uetotal", "");
|
||||
|
||||
if($enread) {
|
||||
my $eu = $u =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etot = ReadingsNum ($consumer, $enread, 0) * $eu; # Summe Energieverbrauch des Verbrauchers
|
||||
my $ehist = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "csmt${c}", undef); # gespeicherter Totalverbrauch
|
||||
$pthreshold = ConsumerVal ($hash, $c, "powerthreshold", 0); # Schwellenwert (Wh pro Stunde) ab der ein Verbraucher als aktiv gewertet wird
|
||||
|
||||
## aktuelle Leitung ermitteln wenn kein Reading d. aktuellen Leistung verfügbar
|
||||
################################################################################
|
||||
if(!$paread){
|
||||
my $timespan = $t - ConsumerVal ($hash, $c, "old_etottime", $t);
|
||||
my $delta = $etot - ConsumerVal ($hash, $c, "old_etotal", $etot);
|
||||
$pcurr = sprintf("%.6f", $delta / (3600 * $timespan)) if($delta > 0); # Einheitenformel beachten !!: W = Wh / (3600 * s)
|
||||
|
||||
$data{$type}{$name}{consumers}{$c}{old_etotal} = $etot;
|
||||
$data{$type}{$name}{consumers}{$c}{old_etottime} = $t;
|
||||
|
||||
push @$daref, "consumer${c}_currentPower<>". $pcurr." W";
|
||||
}
|
||||
@ -2629,34 +2662,63 @@ sub _manageConsumerData {
|
||||
deleteReadingspec ($hash, "consumer${c}_currentPower");
|
||||
}
|
||||
|
||||
## Verbrauch auslesen + speichern
|
||||
##################################
|
||||
my $enread = $acref->{$c}{retotal};
|
||||
my $u = $acref->{$c}{uetotal};
|
||||
if($enread) {
|
||||
my $eu = $u =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etot = ReadingsNum ($consumer, $enread, 0) * $eu; # Summe Energieverbrauch des Verbrauchers
|
||||
my $ehist = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "csmt${c}", undef); # gespeicherter Totalverbrauch
|
||||
my $pthreshold = ConsumerVal ($hash, $c, "powerthreshold", 0); # Schwellenwert (Wh pro Stunde) ab der ein Verbraucher als aktiv gewertet wird
|
||||
|
||||
if(defined $ehist && $etot >= $ehist && ($etot - $ehist) >= $pthreshold) {
|
||||
my $consumerco = $etot - $ehist;
|
||||
$consumerco += HistoryVal ($hash, $day, sprintf("%02d",$nhour), "csme${c}", 0);
|
||||
|
||||
$paref->{consumerco} = $consumerco;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{nhour} = sprintf("%02d",$nhour); # Verbrauch des Consumers aktuelle Stunde
|
||||
$paref->{histname} = "csme${c}";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
}
|
||||
|
||||
$paref->{consumerco} = $etot;
|
||||
$paref->{consumerco} = $etot; # Totalverbrauch des Verbrauchers
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{histname} = "csmt${c}";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
}
|
||||
|
||||
## Verbraucher - Laufzeit und Zyklen pro Tag ermitteln
|
||||
## Laufzeit (in Minuten) wird pro Stunde erfasst
|
||||
## bei Tageswechsel Rücksetzen in _specialActivities
|
||||
#######################################################
|
||||
my $nompower = ConsumerVal ($hash, $c, "power", 0); # nominale Leistung lt. Typenschild
|
||||
my $rpcurr = ConsumerVal ($hash, $c, "rpcurr", ""); # Reading für akt. Verbrauch angegeben ?
|
||||
my $swstate = ConsumerVal ($hash, $c, "state", "undef"); # Schaltzustand des Consumerdevices
|
||||
|
||||
if (!$rpcurr && $swstate eq "on") { # Workaround wenn Verbraucher ohne Leistungsmessung
|
||||
$pcurr = $nompower;
|
||||
}
|
||||
|
||||
my $currpowerpercent = $pcurr;
|
||||
$currpowerpercent = (($pcurr / $nompower) * 100) if($nompower > 0);
|
||||
|
||||
$data{$type}{$name}{consumers}{$c}{currpowerpercent} = $currpowerpercent;
|
||||
|
||||
if($pcurr > $pthreshold || $currpowerpercent > $defpopercent) {
|
||||
if($data{$type}{$name}{consumers}{$c}{onoff} ne "on") {
|
||||
$data{$type}{$name}{consumers}{$c}{startTime} = $t;
|
||||
$data{$type}{$name}{consumers}{$c}{onoff} = "on";
|
||||
my $stimes = ConsumerVal ($hash, $c, "numberDayStarts", 0); # Anzahl der On-Schaltungen am Tag
|
||||
$data{$type}{$name}{consumers}{$c}{numberDayStarts} = $stimes+1;
|
||||
}
|
||||
|
||||
my $starthour = strftime "%H", localtime(ConsumerVal ($hash, $c, "startTime", $t));
|
||||
|
||||
if($chour eq $starthour) {
|
||||
my $runtime = ($t - ConsumerVal ($hash, $c, "startTime", $t)) / 60 ; # in Minuten ! (gettimeofday sind ms !)
|
||||
$data{$type}{$name}{consumers}{$c}{minutesOn} = ConsumerVal ($hash, $c, "minutesOn", 0) + $runtime;
|
||||
}
|
||||
else {
|
||||
$data{$type}{$name}{consumers}{$c}{minutesOn} = 0; # neue Stunde hat begonnen
|
||||
}
|
||||
}
|
||||
else {
|
||||
$data{$type}{$name}{consumers}{$c}{onoff} = "off";
|
||||
}
|
||||
|
||||
## Durchschnittsverbrauch / Betriebszeit ermitteln + speichern
|
||||
################################################################
|
||||
my $consumerco = 0;
|
||||
@ -3852,6 +3914,7 @@ sub entryGraphic {
|
||||
lang => AttrVal ("global", 'language', 'EN'),
|
||||
flowgh => AttrVal ($name, 'flowGraphicSize', $defflowGSize), # Größe Energieflußgrafik
|
||||
flowgani => AttrVal ($name, 'flowGraphicAnimate', 0), # Animation Energieflußgrafik
|
||||
flowgcons => AttrVal ($name, 'flowGraphicShowConsumer', 1), # Verbraucher in der Energieflußgrafik anzeigen
|
||||
css => AttrVal ($name, 'Css', $cssdef), # Css Styles
|
||||
};
|
||||
|
||||
@ -5030,10 +5093,11 @@ sub _flowGraphic {
|
||||
my $name = $paref->{name};
|
||||
my $flowgh = $paref->{flowgh};
|
||||
my $flowgani = $paref->{flowgani};
|
||||
my $flowgcons = $paref->{flowgcons};
|
||||
my $css = $paref->{css};
|
||||
|
||||
my $style = 'width:'.$flowgh.'px; height:'.$flowgh.'px;';
|
||||
my $fs = $flowgh < 300 ? '48px' : '32px';
|
||||
# my $fs = $flowgh < 300 ? '48px' : '32px';
|
||||
my $animation = $flowgani ? '@keyframes dash { to { stroke-dashoffset: 0; } }' : ''; # Animation Ja/Nein
|
||||
|
||||
my $cpv = ReadingsNum($name, 'Current_PV', 0);
|
||||
@ -5048,6 +5112,8 @@ sub _flowGraphic {
|
||||
my $csc = ReadingsNum($name, 'Current_SelfConsumption', 0);
|
||||
my $csc_style = $csc ? 'flowg active_out' : 'flowg inactive_out';
|
||||
|
||||
my $cc = ReadingsNum($name, 'Current_Consumption', 0);
|
||||
|
||||
my $batin = ReadingsNum($name, 'Current_PowerBatIn', undef);
|
||||
my $batout = ReadingsNum($name, 'Current_PowerBatOut', undef);
|
||||
my $soc = ReadingsNum($name, 'Current_BatCharge', 100);
|
||||
@ -5122,13 +5188,17 @@ END0
|
||||
|
||||
## get consumer list and display it in Graphics
|
||||
################################################
|
||||
my $type = $hash->{TYPE};
|
||||
my @consumers = sort{$a<=>$b} keys %{$data{$type}{$name}{consumers}}; # definierte Verbraucher ermitteln
|
||||
my $consumercount = scalar @consumers;
|
||||
my $pos_left = 0;
|
||||
my $consumercount = 0;
|
||||
my $consumer_start = 0;
|
||||
my $consumer_distance = 100;
|
||||
my @consumers;
|
||||
my $currentPower = 0;
|
||||
|
||||
my $currentPower;
|
||||
if ($flowgcons) {
|
||||
my $type = $hash->{TYPE};
|
||||
@consumers = sort{$a<=>$b} keys %{$data{$type}{$name}{consumers}}; # definierte Verbraucher ermitteln
|
||||
$consumercount = scalar @consumers;
|
||||
|
||||
if ($consumercount % 2) {
|
||||
$consumer_start = 250 - ($consumer_distance * (($consumercount -1) / 2));
|
||||
@ -5138,7 +5208,7 @@ END0
|
||||
}
|
||||
|
||||
$consumer_start = 0 if $consumer_start < 0;
|
||||
my $pos_left = $consumer_start + 15;
|
||||
$pos_left = $consumer_start + 15;
|
||||
|
||||
for my $c0 (@consumers) {
|
||||
my $calias = ConsumerVal ($hash, $c0, "alias", ""); # Name des Consumerdevices
|
||||
@ -5151,6 +5221,7 @@ END0
|
||||
|
||||
$pos_left += $consumer_distance;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasbat) {
|
||||
$ret .= << "END1";
|
||||
@ -5182,6 +5253,7 @@ END3
|
||||
|
||||
## get consumer list and display it in Graphics
|
||||
################################################
|
||||
if ($flowgcons) {
|
||||
$pos_left = $consumer_start * 2;
|
||||
my $pos_left_start = 0;
|
||||
my $distance = 25;
|
||||
@ -5207,7 +5279,7 @@ END3
|
||||
$p = (($currentPower / $power) * 100) if ($power > 0);
|
||||
|
||||
my $consumer_style = 'flowg inactive_out';
|
||||
$consumer_style = 'flowg active_out' if($p > 0.5);
|
||||
$consumer_style = 'flowg active_out' if($p > $defpopercent);
|
||||
|
||||
my $consumer_color = "";
|
||||
$consumer_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($p > 0.5);
|
||||
@ -5217,17 +5289,20 @@ END3
|
||||
$pos_left += ($consumer_distance * 2);
|
||||
$pos_left_start += $distance;
|
||||
}
|
||||
}
|
||||
|
||||
$ret .= qq{<text class="flowg text" id="pv-txt" x="600" y="15" style="font-size: $fs; text-anchor: start;">$cpv</text>} if ($cpv);
|
||||
$ret .= qq{<text class="flowg text" id="bat-txt" x="795" y="370" style="font-size: $fs; text-anchor: middle;">$soc %</text>} if ($hasbat);
|
||||
$ret .= qq{<text class="flowg text" id="pv_home-txt" x="530" y="300" style="font-size: $fs; text-anchor: start;">$csc</text>} if ($csc && $cpv);
|
||||
$ret .= qq{<text class="flowg text" id="pv-grid-txt" x="325" y="200" style="font-size: $fs; text-anchor: end;">$cgfi</text>} if ($cgfi);
|
||||
$ret .= qq{<text class="flowg text" id="grid-home-txt" x="325" y="420" style="font-size: $fs; text-anchor: end;">$cgc</text>} if ($cgc);
|
||||
$ret .= qq{<text class="flowg text" id="batout-txt" x="665" y="420" style="font-size: $fs; text-anchor: start;">$batout</text>} if ($batout && $hasbat);
|
||||
$ret .= qq{<text class="flowg text" id="batin-txt" x="665" y="200" style="font-size: $fs; text-anchor: start;">$batin</text>} if ($batin && $hasbat);
|
||||
$ret .= qq{<text class="flowg text" id="pv-txt" x="600" y="15" style="text-anchor: start;">$cpv</text>} if ($cpv);
|
||||
$ret .= qq{<text class="flowg text" id="bat-txt" x="795" y="370" style="text-anchor: middle;">$soc %</text>} if ($hasbat);
|
||||
$ret .= qq{<text class="flowg text" id="pv_home-txt" x="530" y="300" style="text-anchor: start;">$csc</text>} if ($csc && $cpv);
|
||||
$ret .= qq{<text class="flowg text" id="pv-grid-txt" x="325" y="200" style="text-anchor: end;">$cgfi</text>} if ($cgfi);
|
||||
$ret .= qq{<text class="flowg text" id="grid-home-txt" x="325" y="420" style="text-anchor: end;">$cgc</text>} if ($cgc);
|
||||
$ret .= qq{<text class="flowg text" id="batout-txt" x="665" y="420" style="text-anchor: start;">$batout</text>} if ($batout && $hasbat);
|
||||
$ret .= qq{<text class="flowg text" id="batin-txt" x="665" y="200" style="text-anchor: start;">$batin</text>} if ($batin && $hasbat);
|
||||
# $ret .= qq{<text class="flowg text" id="home-txt" x="600" y="620" style="text-anchor: start;">$cc</text>}; # Current_Consumption Anlage
|
||||
|
||||
## get consumer list and display it in Graphics
|
||||
################################################
|
||||
if ($flowgcons) {
|
||||
$pos_left = ($consumer_start * 2) - 50;
|
||||
|
||||
for my $c2 (@consumers) {
|
||||
@ -5239,9 +5314,10 @@ END3
|
||||
$currentPower = $swstate eq "on" ? 'on' : 'off';
|
||||
}
|
||||
|
||||
$ret .= qq{<text class="flowg text" id="consumer-txt_$c2" x="$pos_left" y="1070" style="font-size: $fs; text-anchor: start;">$currentPower</text>};
|
||||
$ret .= qq{<text class="flowg text" id="consumer-txt_$c2" x="$pos_left" y="1070" style="text-anchor: start;">$currentPower</text>}; # Current_Consumption Consumer
|
||||
$pos_left += ($consumer_distance * 2);
|
||||
}
|
||||
}
|
||||
|
||||
$ret .= qq{</g></svg>};
|
||||
|
||||
@ -7551,7 +7627,7 @@ Ein/Ausschaltzeiten sowie deren Ausführung vom SolarForecast Modul übernehmen
|
||||
Zum Ändern des Css-Attributes bitte den Default übernehmen und anpassen: <br><br>
|
||||
|
||||
<ul>
|
||||
.flowg.text { stroke: none; fill: gray; } <br>
|
||||
.flowg.text { stroke: none; fill: gray; font-size: 32px; } <br>
|
||||
.flowg.sun_active { stroke: orange; fill: orange; } <br>
|
||||
.flowg.sun_inactive { stroke: gray; fill: gray; } <br>
|
||||
.flowg.bat25 { stroke: red; fill: red; } <br>
|
||||
@ -7589,6 +7665,13 @@ Ein/Ausschaltzeiten sowie deren Ausführung vom SolarForecast Modul übernehmen
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-flowGraphicShowConsumer"></a>
|
||||
<li><b>flowGraphicShowConsumer </b><br>
|
||||
Unterdrückt die Anzeige der Verbraucher in der Energieflußgrafik wenn auf "0" gesetzt. <br>
|
||||
(default: 1)
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-flowGraphicSize"></a>
|
||||
<li><b>flowGraphicSize <Pixel> </b><br>
|
||||
Größe der Energieflußgrafik sofern angezeigt.
|
||||
|
Loading…
Reference in New Issue
Block a user