2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-24 21:34:51 +00:00

76_SolarForecast: add temporary Migrate Getter x_migrate, Implementation of a Messaging System

git-svn-id: https://svn.fhem.de/fhem/trunk@29537 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2025-01-19 19:45:17 +00:00
parent 0ef7cd3501
commit 72ffc7d6f8
3 changed files with 843 additions and 359 deletions

View File

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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 # Do not insert empty lines here, update check depends on it
- feature: 76_SolarForecast: add temporary Migrate Getter x_migrate,
Implementation of a Messaging System
- change: 49_SSCam: fix Warning, set verified Version to 9.2.2 - change: 49_SSCam: fix Warning, set verified Version to 9.2.2
- change: 76_SolarForecast: internal code change for data collection - change: 76_SolarForecast: internal code change for data collection
- change: 76_SolarForecast: FlowGraphic: SoC as a Cluster value of all Batts - change: 76_SolarForecast: FlowGraphic: SoC as a Cluster value of all Batts

File diff suppressed because it is too large Load Diff

View File

@ -157,8 +157,9 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.43.7" => "19.01.2025 _listDataPoolCircular: may select a dedicated hour, add temporary Migrate funktion ". "1.44.0" => "19.01.2025 _listDataPoolCircular: may select a dedicated hour, add temporary Migrate funktion x_migrate ".
"fix interruptable key check in consumer attr Forum:https://forum.fhem.de/index.php?msg=1331073 ", "fix interruptable key check in consumer attr Forum:https://forum.fhem.de/index.php?msg=1331073 ".
"set prdef to 1.0, Implementation of a Messaging System ",
"1.43.6" => "17.01.2025 _calcCaQcomplex: additional write pvrl, pvfc to separate circular hash Array elements, listDataPool: show these Arrays ", "1.43.6" => "17.01.2025 _calcCaQcomplex: additional write pvrl, pvfc to separate circular hash Array elements, listDataPool: show these Arrays ",
"1.43.5" => "15.01.2025 _flowGraphic: calculate the resulting SoC as a cluster of batteries ", "1.43.5" => "15.01.2025 _flowGraphic: calculate the resulting SoC as a cluster of batteries ",
"1.43.4" => "14.01.2025 batsocslidereg: calculate the SoC as summary over all capacities in Wh, bugfix https://forum.fhem.de/index.php?msg=1330559 ", "1.43.4" => "14.01.2025 batsocslidereg: calculate the SoC as summary over all capacities in Wh, bugfix https://forum.fhem.de/index.php?msg=1330559 ",
@ -432,7 +433,7 @@ my $ometmaxreq = 9700;
my $leadtime = 3600; # relative Zeit vor Sonnenaufgang zur Freigabe API Abruf / Verbraucherplanung my $leadtime = 3600; # relative Zeit vor Sonnenaufgang zur Freigabe API Abruf / Verbraucherplanung
my $lagtime = 1800; # Nachlaufzeit relativ zu Sunset bis Sperrung API Abruf my $lagtime = 1800; # Nachlaufzeit relativ zu Sunset bis Sperrung API Abruf
my $prdef = 0.85; # default Performance Ratio (PR) my $prdef = 1.0; # default Performance Ratio (PR)
my $tempcoeffdef = -0.45; # default Temperaturkoeffizient Pmpp (%/°C) lt. Datenblatt Solarzelle my $tempcoeffdef = -0.45; # default Temperaturkoeffizient Pmpp (%/°C) lt. Datenblatt Solarzelle
my $tempmodinc = 25; # default Temperaturerhöhung an Solarzellen gegenüber Umgebungstemperatur bei wolkenlosem Himmel my $tempmodinc = 25; # default Temperaturerhöhung an Solarzellen gegenüber Umgebungstemperatur bei wolkenlosem Himmel
my $tempbasedef = 25; # Temperatur Module bei Nominalleistung my $tempbasedef = 25; # Temperatur Module bei Nominalleistung
@ -573,8 +574,16 @@ for my $pn (1..$maxproducer) {
my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select|bitfield|widgetList|colorpicker'; my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select|bitfield|widgetList|colorpicker';
# Steuerhashes ## Steuerhashes
################ #########################
my %msgs = (); # Initialisierung Mitteilungssystem
my %svicons = ( # Schweregrad Icons Mitteilungssystem
'0' => 'message_mail@grey', # Standard Mitteilungs-Icon 0 - keine Mitteilung
'1' => 'message_postbox_mail@darkorange', # Standard Mitteilungs-Icon 1 - Mitteilung
'2' => 'message_attention@darkorange', # Standard Mitteilungs-Icon 2 - Warnung
'3' => 'message_attention@red', # Standard Mitteilungs-Icon 3 - Fehler / Problem
);
my %hset = ( # Hash der Set-Funktion my %hset = ( # Hash der Set-Funktion
consumerImmediatePlanning => { fn => \&_setconsumerImmediatePlanning }, consumerImmediatePlanning => { fn => \&_setconsumerImmediatePlanning },
@ -634,7 +643,8 @@ my %hget = ( # Ha
valDecTree => { fn => \&_getaiDecTree, needcred => 0 }, valDecTree => { fn => \&_getaiDecTree, needcred => 0 },
ftuiFramefiles => { fn => \&_ftuiFramefiles, needcred => 0 }, ftuiFramefiles => { fn => \&_ftuiFramefiles, needcred => 0 },
dwdCatalog => { fn => \&_getdwdCatalog, needcred => 0 }, dwdCatalog => { fn => \&_getdwdCatalog, needcred => 0 },
'.migrate' => { fn => \&_getmigrate, needcred => 0 }, outputMessages => { fn => \&_getoutputMessages, needcred => 0 },
x_migrate => { fn => \&_getmigrate, needcred => 0 },
); );
my %hattr = ( # Hash für Attr-Funktion my %hattr = ( # Hash für Attr-Funktion
@ -792,6 +802,14 @@ my %hqtxt = ( # H
DE => qq{Verbrauch} }, DE => qq{Verbrauch} },
tday => { EN => qq{today}, tday => { EN => qq{today},
DE => qq{heute} }, DE => qq{heute} },
simsg => { EN => qq{Message},
DE => qq{Mitteilung} },
msgsys => { EN => qq{Messaging system},
DE => qq{Mitteilungssystem} },
msgimp => { EN => qq{Importance},
DE => qq{Wichtigkeit} },
number => { EN => qq{Number},
DE => qq{Nummer} },
ctnsly => { EN => qq{continuously}, ctnsly => { EN => qq{continuously},
DE => qq{fortlaufend} }, DE => qq{fortlaufend} },
yday => { EN => qq{yesterday}, yday => { EN => qq{yesterday},
@ -941,6 +959,10 @@ my %htitles = (
DE => qq{Öffne das SolarForecast Forum} }, DE => qq{Öffne das SolarForecast Forum} },
opwiki => { EN => qq{Open the Wiki (German language)}, opwiki => { EN => qq{Open the Wiki (German language)},
DE => qq{Öffne das Wiki} }, DE => qq{Öffne das Wiki} },
outpmsg => { EN => qq{Messages are available - press the button to open them},
DE => qq{Mitteilungen sind vorhanden - drücke die Taste um sie zu Öffnen} },
nomsgfo => { EN => qq{there is no message available},
DE => qq{es ist keine Mitteilung vorhanden} },
scaresps => { EN => qq{API request successful}, scaresps => { EN => qq{API request successful},
DE => qq{API Abfrage erfolgreich} }, DE => qq{API Abfrage erfolgreich} },
dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model}, dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model},
@ -1169,8 +1191,8 @@ my %hcsr = (
# Funktiontemplate zur Speicherung von Werten in pvHistory # Funktiontemplate zur Speicherung von Werten in pvHistory
# storname = Name des Elements in der pvHistory # storname = Name des Elements in der pvHistory
# nhour = evtl. abweichend von $nhour # nhour = evtl. abweichend von $nhour
# fpar = Parameter zur spezifischen Verwendung # fpar = Parameter zur spezifischen Verwendung
my %hfspvh = ( my %hfspvh = (
radiation => { fn => \&_storeVal, storname => 'rad1h', validkey => undef, fpar => undef }, # irradiation radiation => { fn => \&_storeVal, storname => 'rad1h', validkey => undef, fpar => undef }, # irradiation
DoN => { fn => \&_storeVal, storname => 'DoN', validkey => undef, fpar => undef }, # Tag 1 oder Nacht 0 DoN => { fn => \&_storeVal, storname => 'DoN', validkey => undef, fpar => undef }, # Tag 1 oder Nacht 0
@ -1902,7 +1924,7 @@ return;
} }
################################################################ ################################################################
# Setter plantConfiguration # Setter / (verborgener) Getter plantConfiguration
################################################################ ################################################################
sub _setplantConfiguration { ## no critic "not used" sub _setplantConfiguration { ## no critic "not used"
my $paref = shift; my $paref = shift;
@ -2477,9 +2499,12 @@ sub Get {
"radiationApiData:noArg ". "radiationApiData:noArg ".
"statusApiData:noArg ". "statusApiData:noArg ".
"valCurrent:noArg ". "valCurrent:noArg ".
#".migrate:noArg ".
"weatherApiData:noArg " "weatherApiData:noArg "
; ;
if (!ReadingsVal ($name, '.migrated', 0)) {
$getlist .= "x_migrate:noArg ";
}
## KI spezifische Getter ## KI spezifische Getter
########################## ##########################
@ -2521,7 +2546,7 @@ return $getlist;
} }
################################################################ ################################################################
# Getter .migrate # Getter x_migrate
################################################################ ################################################################
sub _getmigrate { ## no critic "not used" sub _getmigrate { ## no critic "not used"
my $paref = shift; my $paref = shift;
@ -2532,8 +2557,8 @@ sub _getmigrate { ## no critic "not used"
########################################################################################################################## ##########################################################################################################################
my $n = 0; my $n = 0;
if (!exists $hash->{HELPER}{MIGDONE}) { if (!ReadingsVal ($name, '.migrated', 0)) {
for my $hh (1..24) { # 18.01.25 -> Datenmigration pvrlsum, pvfcsum, dnumsum in pvrl_*, pvfc_* for my $hh (1..24) { # 19.01.25 -> Datenmigration pvrlsum, pvfcsum, dnumsum in pvrl_*, pvfc_*
$hh = sprintf "%02d", $hh; $hh = sprintf "%02d", $hh;
for my $cul (sort keys %{$data{$name}{circular}{$hh}}) { for my $cul (sort keys %{$data{$name}{circular}{$hh}}) {
@ -2568,9 +2593,9 @@ sub _getmigrate { ## no critic "not used"
} }
#$hash->{HELPER}{MIGDONE} = 1; readingsSingleUpdate ($hash, '.migrated', 1, 0);
return "Circular Store was migrated, $n datasets were processed and deleted"; return "Circular Store was migrated, $n datasets were migrated";
} }
################################################################ ################################################################
@ -4420,15 +4445,15 @@ sub __openMeteoDWD_ApiResponse {
next; # Daten älter als akt. Tag 00:00:00 verwerfen next; # Daten älter als akt. Tag 00:00:00 verwerfen
} }
my $rad1wh = $jdata->{hourly}{global_tilted_irradiance}[$k]; # Wh/m2 my $rad1wh = $jdata->{hourly}{global_tilted_irradiance}[$k]; # Wh/m2
my $rad = 10 * (sprintf "%.0f", ($rad1wh * $WhtokJ) / 10); # Umrechnung Wh/m2 in kJ/m2 -> my $rad = 10 * (sprintf "%.0f", ($rad1wh * $WhtokJ) / 10); # Umrechnung Wh/m2 in kJ/m2 ->
my $pv = sprintf "%.2f", int ($rad1wh / 1000 * $peak * $prdef); # Rad wird in kWh/m2 erwartet my $pv = sprintf "%.2f", int ($rad1wh / 1000 * $peak * $prdef); # Rad wird in kWh/m2 erwartet
my $don = $jdata->{hourly}{is_day}[$k]; my $don = $jdata->{hourly}{is_day}[$k];
my $temp = $jdata->{hourly}{temperature_2m}[$k]; my $temp = $jdata->{hourly}{temperature_2m}[$k];
my $rain = $jdata->{hourly}{rain}[$k]; # Regen in Millimeter = kg/m2 my $rain = $jdata->{hourly}{rain}[$k]; # Regen in Millimeter = kg/m2
my $wid = ($don ? 0 : 100) + $jdata->{hourly}{weather_code}[$k]; my $wid = ($don ? 0 : 100) + $jdata->{hourly}{weather_code}[$k];
my $wcc = $jdata->{hourly}{cloud_cover}[$k]; my $wcc = $jdata->{hourly}{cloud_cover}[$k];
if ($k == 0 && $curwid) { $curwid = ($don ? 0 : 100) + $curwid } if ($k == 0 && $curwid) { $curwid = ($don ? 0 : 100) + $curwid }
@ -4625,6 +4650,44 @@ sub _getftui {
return pageAsHtml ($name, 'ftui', $arg); return pageAsHtml ($name, 'ftui', $arg);
} }
################################################################
# verborgener Getter outputMessages
################################################################
sub _getoutputMessages { ## no critic "not used"
my $paref = shift;
my $name = $paref->{name};
my $hash = $defs{$name};
my $out = outputMessages ($paref);
$out = qq{<html>$out</html>};
## asynchrone Ausgabe
#######################
#$err = getClHash($hash);
#$paref->{out} = $out;
#InternalTimer(gettimeofday()+3, "FHEM::SolarForecast::__plantCfgAsynchOut", $paref, 0);
return $out;
}
###############################################################
# Getter pvQualities
###############################################################
sub _getForecastQualities {
my $paref = shift;
my $name = $paref->{name};
my $arg = $paref->{arg} // q{};
my $hash = $defs{$name};
my $ret = listDataPool ($hash, 'qualities');
if ($arg eq 'imgget') { # Ausgabe aus dem Grafikheader Qualitätsicon
$ret =~ s/\n/<br>/g;
}
return $ret;
}
############################################################### ###############################################################
# Getter pvHistory # Getter pvHistory
############################################################### ###############################################################
@ -4672,24 +4735,6 @@ sub _getlistNextHours {
return $ret; return $ret;
} }
###############################################################
# Getter pvQualities
###############################################################
sub _getForecastQualities {
my $paref = shift;
my $name = $paref->{name};
my $arg = $paref->{arg} // q{};
my $hash = $defs{$name};
my $ret = listDataPool ($hash, 'qualities');
if ($arg eq 'imgget') { # Ausgabe aus dem Grafikheader Qualitätsicon
$ret =~ s/\n/<br>/g;
}
return $ret;
}
############################################################### ###############################################################
# Getter valCurrent # Getter valCurrent
############################################################### ###############################################################
@ -7525,7 +7570,7 @@ sub centralTask {
} }
$data{$name}{current}{ctrunning} = 1; # Central Task running Statusbit $data{$name}{current}{ctrunning} = 1; # Central Task running Statusbit
InternalTimer (gettimeofday() + 1.2, "FHEM::SolarForecast::releaseCentralTask", $hash, 0); # Freigabe centralTask InternalTimer (gettimeofday() + 2.0, "FHEM::SolarForecast::releaseCentralTask", $hash, 0); # Freigabe centralTask
my $t = time; # aktuelle Unix-Zeit my $t = time; # aktuelle Unix-Zeit
my $date = strftime "%Y-%m-%d", localtime($t); # aktuelles Datum my $date = strftime "%Y-%m-%d", localtime($t); # aktuelles Datum
@ -7743,7 +7788,6 @@ return $az;
sub _getMoonPhase { sub _getMoonPhase {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type};
my $t = $paref->{t}; # Epoche Zeit my $t = $paref->{t}; # Epoche Zeit
my $moonphasei; my $moonphasei;
@ -7768,8 +7812,6 @@ return;
sub _collectAllRegConsumers { sub _collectAllRegConsumers {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type};
my $hash = $defs{$name}; my $hash = $defs{$name};
return if(CurrentVal ($hash, 'consumerCollected', 0)); # Abbruch wenn Consumer bereits gesammelt return if(CurrentVal ($hash, 'consumerCollected', 0)); # Abbruch wenn Consumer bereits gesammelt
@ -12276,8 +12318,13 @@ sub _calcCaQcomplex {
$paref->{sabin} = $sabin; $paref->{sabin} = $sabin;
$paref->{calc} = 'Complex'; $paref->{calc} = 'Complex';
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref); my ($oldfac, $factor, $dnum);
#my ($oldfac, $factor, $dnum) = __calcNewFactor_new ($paref); if (!ReadingsVal ($name, '.migrated', 0)) { # Daten wurden noch nicht migriert
($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
}
else {
($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref);
}
delete $paref->{pvrl}; delete $paref->{pvrl};
delete $paref->{pvfc}; delete $paref->{pvfc};
@ -12347,8 +12394,13 @@ sub _calcCaQsimple {
$paref->{crang} = 'simple'; $paref->{crang} = 'simple';
$paref->{calc} = 'Simple'; $paref->{calc} = 'Simple';
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref); my ($oldfac, $factor, $dnum);
#my ($oldfac, $factor, $dnum) = __calcNewFactor_new ($paref); if (!ReadingsVal ($name, '.migrated', 0)) { # Daten wurden noch nicht migriert
($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
}
else {
($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref);
}
delete $paref->{pvrl}; delete $paref->{pvrl};
delete $paref->{pvfc}; delete $paref->{pvfc};
@ -12459,7 +12511,7 @@ return ($oldfac, $factor, $dnum);
################################################################ ################################################################
# den neuen Korrekturfaktur berechnen (neue Funktion) # den neuen Korrekturfaktur berechnen (neue Funktion)
################################################################ ################################################################
sub __calcNewFactor_new { sub __calcNewFactor_migrated {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $pvrl = $paref->{pvrl}; my $pvrl = $paref->{pvrl};
@ -12476,7 +12528,7 @@ sub __calcNewFactor_new {
my ($oldfac, $oldqal) = CircularSunCloudkorrVal ($hash, $hh, $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität my ($oldfac, $oldqal) = CircularSunCloudkorrVal ($hash, $hh, $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität
$oldfac = 1 if(1 * $oldfac == 0); $oldfac = 1 if(1 * $oldfac == 0);
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> Start calculation correction factor for hour: $hh"); debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> Start calculation correction factor for hour: $hh (migrated data structure)");
if ($calc eq 'Simple') { if ($calc eq 'Simple') {
($pvcirc, $fccirc, $dnum) = CircularSumVal ($hash, $hh, $sabin, 'simple', 0); ($pvcirc, $fccirc, $dnum) = CircularSumVal ($hash, $hh, $sabin, 'simple', 0);
@ -13401,10 +13453,12 @@ sub _graphicHeader {
$lup = "$day.$month.$year&nbsp;$time"; $lup = "$day.$month.$year&nbsp;$time";
} }
my $cmdplchk = qq{"FW_cmd('$::FW_ME$::FW_subdir?XHR=1&cmd=get $name plantConfigCheck', function(data){FW_okDialog(data)})"}; # Plant Check Button generieren my $cmdplchk = qq{"FW_cmd('$::FW_ME$::FW_subdir?XHR=1&cmd=get $name plantConfigCheck', function(data){FW_okDialog(data)})"}; # Plant Check Kommando generieren
my $cmdoutmsg = qq{"FW_cmd('$::FW_ME$::FW_subdir?XHR=1&cmd=get $name outputMessages', function(data){FW_okDialog(data)})"}; # Message Ausgabe Kommando generieren
if ($ftui eq 'ftui') { if ($ftui eq 'ftui') {
$cmdplchk = qq{"ftui.setFhemStatus('get $name plantConfigCheck')"}; $cmdplchk = qq{"ftui.setFhemStatus('get $name plantConfigCheck')"};
$cmdoutmsg = qq{"ftui.setFhemStatus('get $name outputMessages')"};
} }
## Anlagen Check-Icon ## Anlagen Check-Icon
@ -13423,8 +13477,15 @@ sub _graphicHeader {
############## ##############
$img = FW_makeImage ('edit_copy@grey'); $img = FW_makeImage ('edit_copy@grey');
my $wikicon = "<a href='https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung' target='_blank'>$img</a>"; my $wikicon = "<a href='https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung' target='_blank'>$img</a>";
my $wiktitle = $htitles{opwiki}{$lang}; my $wiktitle = $htitles{opwiki}{$lang};
## Message-Icon
#################
my ($micon, $midx) = __fillupMessages ($paref);
$img = FW_makeImage ($micon);
my $msgicon = $midx ? "<a onClick=$cmdoutmsg>$img</a>" : $img;
my $msgtitle = $midx ? $htitles{outpmsg}{$lang} : $htitles{nomsgfo}{$lang};
## Update-Icon ## Update-Icon
################ ################
my $upicon = __createUpdateIcon ($paref); my $upicon = __createUpdateIcon ($paref);
@ -13636,7 +13697,7 @@ sub _graphicHeader {
my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname
my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>}; my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>};
my $space = '&nbsp;&nbsp;&nbsp;'; my $space = '&nbsp;&nbsp;&nbsp;';
my $disti = qq{<span title="$chktitle"> $chkicon </span> $space <span title="$fthtitle"> $fthicon </span> $space <span title="$wiktitle"> $wikicon </span>}; my $disti = qq{<span title="$chktitle"> $chkicon </span> $space <span title="$fthtitle"> $fthicon </span> $space <span title="$wiktitle"> $wikicon </span> $space <span title="$msgtitle"> $msgicon </span>};
$header .= qq{<tr>}; $header .= qq{<tr>};
$header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>}; $header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>};
@ -13703,6 +13764,43 @@ sub _graphicHeader {
return $header; return $header;
} }
################################################################
# Mitteilungssystem füllen
# Schweregrad SV:
# 0 - keine Mitteilung
# 1 - Mitteilung
# 2 - Warnung
# 3 - Fehler / Problem
################################################################
sub __fillupMessages {
my $paref = shift;
my $name = $paref->{name};
my $lang = $paref->{lang};
undef %msgs;
my $midx = 0;
my $max_sv = 0;
if (!ReadingsVal ($name, '.migrated', 0)) {
$midx++;
$msgs{$midx}{SV} = 1;
$msgs{$midx}{DE} = 'Die gespeicherten PV Daten können mit "get ... x_migrate" in ein neues Format umgesetzt werden welches den Median Ansatz bei der PV Prognose aktiviert und nutzt.';
$msgs{$midx}{DE} .= '<br>Mit einem späteren Update des Moduls erfolgt diese Umstellung automatisch.';
$msgs{$midx}{EN} = 'The stored PV data can be converted with “get ... x_migrate” into a new format which activates and uses the median approach in the PV forecast.';
$msgs{$midx}{EN} .= '<br>With a later update of the module, this changeover will take place automatically.';
}
if ($midx) {
my @aidx = map { $_ } (1..$midx); # größte vorhandene Severity finden
my @values = map { $msgs{$_}{SV} } @aidx;
$max_sv = max(@values);
}
my $max_icon = $svicons{$max_sv}; # ... und das dazugehörige Icon
return ($max_icon, $midx);
}
################################################################ ################################################################
# erstelle Update-Icon # erstelle Update-Icon
################################################################ ################################################################
@ -18084,6 +18182,60 @@ sub _writeAsCsv {
return "The memory structure was written to the file $outfile"; return "The memory structure was written to the file $outfile";
} }
################################################################
# Ausgabe des Mitteilungsystems
################################################################
sub outputMessages {
my $paref = shift;
my $name = $paref->{name};
my $lang = $paref->{lang};
my ($micon, $midx) = __fillupMessages ($paref); # Ergebnisse füllen (sind leer wenn Browser nicht refreshed)
## Ausgabe
############
my $out = qq{<html>};
$out .= qq{<b>}.$hqtxt{msgsys}{$lang}.qq{</b> <br><br>};
$out .= qq{<table class="roomoverview" style="text-align:left; border:1px solid; padding:5px; border-spacing:5px; margin-left:auto; margin-right:auto;">};
$out .= qq{<tr style="font-weight:bold;">};
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{number}{$lang} </td>};
$out .= qq{<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>};
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{msgimp}{$lang} </td>};
$out .= qq{<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>};
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{simsg}{$lang} </td>};
$out .= qq{</tr>};
$out .= qq{<tr></tr>};
my $hc = 0;
for my $key (sort keys %msgs) {
$hc++;
my $enmsg = encode ("utf8", $msgs{$key}{$lang});
$out .= qq{<tr>};
$out .= qq{<td style="padding: 5px; text-align: center"> $key </td>};
$out .= qq{<td style="padding: 5px;"> </td>};
$out .= qq{<td style="padding: 5px; text-align: center"> $msgs{$key}{SV} </td>};
$out .= qq{<td style="padding: 5px;"> </td>};
$out .= qq{<td style="padding-right: 5px; text-align: left"> $enmsg </td>};
$out .= qq{</tr>};
if ($hc < $midx) { # Zwischenzeile
$out .= qq{<tr>};
$out .= qq{<td> &nbsp; </td>};
$out .= qq{</tr>};
}
}
$out .= qq{</table>};
$out .= qq{</html>};
$out .= "<br>";
return $out;
}
################################################################ ################################################################
# validiert die aktuelle Anlagenkonfiguration # validiert die aktuelle Anlagenkonfiguration
################################################################ ################################################################
@ -18670,7 +18822,7 @@ sub checkPlantConfig {
$out .= "<br>"; $out .= "<br>";
if($cf) { if ($cf) {
$out .= encode ("utf8", $hqtxt{strnok}{$lang}); $out .= encode ("utf8", $hqtxt{strnok}{$lang});
} }
elsif ($wn) { elsif ($wn) {
@ -22346,6 +22498,18 @@ to ensure that the system configuration is correct.
</li> </li>
</ul> </ul>
<br> <br>
<ul>
<a id="SolarForecast-get-x_migrate"></a>
<li><b>x_migrate </b> <br><br>
Migrates the existing PV Real and PV Forecast values in the ring buffer a new data structure. <br>
From the time of the changeover, the correction factors for the PV forecast will be determined using a median calculation
instead of the previous average calculation. <br><br>
<b>x_migrate is a special function. Please clarify any ambiguities in the SolarForecast forum before execution! </b>
</li>
</ul>
<br>
</ul> </ul>
<br> <br>
@ -22623,10 +22787,10 @@ to ensure that the system configuration is correct.
<b>attr &lt;name&gt; consumer01</b> wallplug icon=scene_dishwasher@orange type=dishwasher mode=can power=2500 on=on off=off notafter=20 etotal=total:kWh:5 <br> <b>attr &lt;name&gt; consumer01</b> wallplug icon=scene_dishwasher@orange type=dishwasher mode=can power=2500 on=on off=off notafter=20 etotal=total:kWh:5 <br>
<b>attr &lt;name&gt; consumer02</b> WPxw type=heater mode=can power=3000 mintime=180 on="on-for-timer 3600" notafter=12 auto=automatic <br> <b>attr &lt;name&gt; consumer02</b> WPxw type=heater mode=can power=3000 mintime=180 on="on-for-timer 3600" notafter=12 auto=automatic <br>
<b>attr &lt;name&gt; consumer03</b> Shelly.shellyplug2 type=other power=300 mode=must icon=it_ups_on_battery mintime=120 on=on off=off swstate=state:on:off auto=automatic pcurr=relay_0_power:W etotal:relay_0_energy_Wh:Wh swoncond=EcoFlow:data_data_socSum:-?([1-7][0-9]|[0-9]) swoffcond:EcoFlow:data_data_socSum:100 <br> <b>attr &lt;name&gt; consumer03</b> Shelly.shellyplug2 type=other power=300 mode=must icon=it_ups_on_battery mintime=120 on=on off=off swstate=state:on:off auto=automatic pcurr=relay_0_power:W etotal:relay_0_energy_Wh:Wh swoncond=EcoFlow:data_data_socSum:-?([1-7][0-9]|[0-9]) swoffcond:EcoFlow:data_data_socSum:100 <br>
<b>attr &lt;name&gt; consumer04</b> Shelly.shellyplug3 icon=scene_microwave_oven@ed type=heater power=2000 mode=must notbefore=07 mintime=600 on=on off=off etotal=relay_0_energy_Wh:Wh pcurr=relay_0_power:W auto=automatic interruptable=eg.wz.wandthermostat:diff-temp:(22)(\.[2-9])|([2-9][3-9])(\.[0-9]):0.2 <br> <b>attr &lt;name&gt; consumer04</b> Shelly.shellyplug3 icon=scene_microwave_oven@ed type=heater power=2000 mode=must notbefore=07 mintime=600 on=on off=off etotal=relay_0_energy_Wh:Wh pcurr=relay_0_power:W auto=automatic interruptable=eg.wz.wandthermostat:diff-temp:(22)(\.[2-9])|([2-9][3-9])(\.[0-9]):0.2 <br>
<b>attr &lt;name&gt; consumer05</b> Shelly.shellyplug4 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=7 notafter=20:10 auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath interruptable=1 <br> <b>attr &lt;name&gt; consumer05</b> Shelly.shellyplug4 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=7 notafter=20:10 auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath interruptable=1 <br>
<b>attr &lt;name&gt; consumer06</b> Shelly.shellyplug5 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=07:05 notafter={return'20:05'} auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath:60:-120 interruptable=1 <br> <b>attr &lt;name&gt; consumer06</b> Shelly.shellyplug5 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=07:05 notafter={return'20:05'} auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath:60:-120 interruptable=1 <br>
<b>attr &lt;name&gt; consumer07</b> SolCastDummy icon=sani_buffer_electric_heater_side type=heater mode=can power=600 auto=automatic pcurr=actpow:W on=on off=off mintime=15 asynchron=1 locktime=300:1200 interruptable=1 noshow=noShow <br> <b>attr &lt;name&gt; consumer07</b> SolCastDummy icon=sani_buffer_electric_heater_side type=heater mode=can power=600 auto=automatic pcurr=actpow:W on=on off=off mintime=15 asynchron=1 locktime=300:1200 interruptable=1 noshow=1 <br>
</ul> </ul>
</li> </li>
<br> <br>
@ -24817,6 +24981,18 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</li> </li>
</ul> </ul>
<br> <br>
<ul>
<a id="SolarForecast-get-x_migrate"></a>
<li><b>x_migrate </b> <br><br>
Migriert die vorhandenen PV Real und PV Forecast Werte im Ringspeicher in eine neue Datenstruktur. <br>
Ab dem Zeitpunkt der Umstellung werden die Korrekturfaktoren für die PV Vorhersage über eine Median Berechnung
statt der bisherigen Durchschnittberechnung ermittelt. <br><br>
<b>x_migrate ist eine spezielle Funktion. Unklarheiten bitte vor Ausführung im SolarForecast Forum klären! </b>
</li>
</ul>
<br>
</ul> </ul>
<br> <br>
@ -25096,7 +25272,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<b>attr &lt;name&gt; consumer04</b> Shelly.shellyplug3 icon=scene_microwave_oven@red type=heater power=2000 mode=must notbefore=07 mintime=600 on=on off=off etotal=relay_0_energy_Wh:Wh pcurr=relay_0_power:W auto=automatic interruptable=eg.wz.wandthermostat:diff-temp:(22)(\.[2-9])|([2-9][3-9])(\.[0-9]):0.2 <br> <b>attr &lt;name&gt; consumer04</b> Shelly.shellyplug3 icon=scene_microwave_oven@red type=heater power=2000 mode=must notbefore=07 mintime=600 on=on off=off etotal=relay_0_energy_Wh:Wh pcurr=relay_0_power:W auto=automatic interruptable=eg.wz.wandthermostat:diff-temp:(22)(\.[2-9])|([2-9][3-9])(\.[0-9]):0.2 <br>
<b>attr &lt;name&gt; consumer05</b> Shelly.shellyplug4 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=7 notafter=20:10 auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath interruptable=1 <br> <b>attr &lt;name&gt; consumer05</b> Shelly.shellyplug4 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=7 notafter=20:10 auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath interruptable=1 <br>
<b>attr &lt;name&gt; consumer06</b> Shelly.shellyplug5 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=07:20 notafter={return'20:05'} auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath:60:-120 interruptable=1 <br> <b>attr &lt;name&gt; consumer06</b> Shelly.shellyplug5 icon=sani_buffer_electric_heater_side type=heater mode=must power=1000 notbefore=07:20 notafter={return'20:05'} auto=automatic pcurr=actpow:W on=on off=off mintime=SunPath:60:-120 interruptable=1 <br>
<b>attr &lt;name&gt; consumer07</b> SolCastDummy icon=sani_buffer_electric_heater_side type=heater mode=can power=600 auto=automatic pcurr=actpow:W on=on off=off mintime=15 asynchron=1 locktime=300:1200 interruptable=1 noshow=noShow <br> <b>attr &lt;name&gt; consumer07</b> SolCastDummy icon=sani_buffer_electric_heater_side type=heater mode=can power=600 auto=automatic pcurr=actpow:W on=on off=off mintime=15 asynchron=1 locktime=300:1200 interruptable=1 noshow=1 <br>
</ul> </ul>
</li> </li>
<br> <br>