2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

76_SolarForecast: Setter writeHistory replaced by operatingMemory save, backup and recover in-memory operating data

git-svn-id: https://svn.fhem.de/fhem/trunk@28432 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-01-27 19:12:50 +00:00
parent a454d5eb4f
commit aad0ac51ac
2 changed files with 331 additions and 226 deletions

View File

@ -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.
- feature: 76_SolarForecast: Setter writeHistory replaced by operatingMemory
save, backup and recover in-memory operating data
- feature: 76_SolarForecast: generate plant backup files
- bugfix: 76_SolarForecast: minor fixes
- feature: 76_SolarForecast: consumerXX: notbefore, notafter can be {<code>}

View File

@ -157,6 +157,8 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"1.13.0" => "27.01.2024 minor change of deleteOldBckpFiles, Setter writeHistory replaced by operatingMemory ".
"save, backup and recover in-memory operating data ",
"1.12.0" => "26.01.2024 create backup files and delete old generations of them ",
"1.11.1" => "26.01.2024 fix ___switchonTimelimits ",
"1.11.0" => "25.01.2024 consumerXX: notbefore, notafter format extended to possible perl code {...} ",
@ -439,7 +441,7 @@ my %hset = ( # Ha
moduleRoofTops => { fn => \&_setmoduleRoofTops },
moduleTiltAngle => { fn => \&_setmoduleTiltAngle },
moduleDirection => { fn => \&_setmoduleDirection },
writeHistory => { fn => \&_setwriteHistory },
operatingMemory => { fn => \&_setoperatingMemory },
vrmCredentials => { fn => \&_setVictronCredentials },
aiDecTree => { fn => \&_setaiDecTree },
);
@ -913,6 +915,7 @@ sub Initialize {
"ctrlAIdataStorageDuration ".
"ctrlAutoRefresh:selectnumbers,120,0.2,1800,0,log10 ".
"ctrlAutoRefreshFW:$fwd ".
"ctrlBackupFilesKeep:select,1,2,3,4,5,6,7,8,9,10 ".
"ctrlBatSocManagement:textField-long ".
"ctrlConsRecommendReadings:multiple-strict,$allcs ".
"ctrlDebug:multiple-strict,$dm,#14 ".
@ -1008,26 +1011,32 @@ sub Define {
$params->{file} = $pvhcache.$name; # Cache File PV History einlesen wenn vorhanden
$params->{cachename} = 'pvhist';
$params->{title} = 'pvHistory';
_readCacheFile ($params);
$params->{file} = $pvccache.$name; # Cache File PV Circular einlesen wenn vorhanden
$params->{cachename} = 'circular';
$params->{title} = 'pvCircular';
_readCacheFile ($params);
$params->{file} = $csmcache.$name; # Cache File Consumer einlesen wenn vorhanden
$params->{cachename} = 'consumers';
$params->{title} = 'consumerMaster';
_readCacheFile ($params);
$params->{file} = $scpicache.$name; # Cache File SolCast API Werte einlesen wenn vorhanden
$params->{cachename} = 'solcastapi';
$params->{title} = 'solApiData';
_readCacheFile ($params);
$params->{file} = $aitrained.$name; # AI Cache File einlesen wenn vorhanden
$params->{cachename} = 'aitrained';
$params->{title} = 'aiTrainedData';
_readCacheFile ($params);
$params->{file} = $airaw.$name; # AI Rawdaten File einlesen wenn vorhanden
$params->{cachename} = 'airaw';
$params->{title} = 'aiRawData';
_readCacheFile ($params);
singleUpdateState ( {hash => $hash, state => 'initialized', evt => 1} );
@ -1048,6 +1057,7 @@ sub _readCacheFile {
my $type = $paref->{type};
my $file = $paref->{file};
my $cachename = $paref->{cachename};
my $title = $paref->{title};
if ($cachename eq 'aitrained') {
my ($err, $dtree) = fileRetrieve ($file);
@ -1058,7 +1068,7 @@ sub _readCacheFile {
if ($valid) {
$data{$type}{$name}{aidectree}{aitrained} = $dtree;
$data{$type}{$name}{current}{aitrainstate} = 'ok';
Log3 ($name, 3, qq{$name - cached data "$cachename" restored});
Log3 ($name, 3, qq{$name - cached data "$title" restored});
}
}
@ -1071,7 +1081,7 @@ sub _readCacheFile {
if (!$err && $data) {
$data{$type}{$name}{aidectree}{airaw} = $data;
$data{$type}{$name}{current}{aitrawstate} = 'ok';
Log3 ($name, 3, qq{$name - cached data "$cachename" restored});
Log3 ($name, 3, qq{$name - cached data "$title" restored});
}
return;
@ -1079,16 +1089,16 @@ sub _readCacheFile {
my ($error, @content) = FileRead ($file);
if(!$error) {
if (!$error) {
my $json = join "", @content;
my ($success) = evaljson ($hash, $json);
if($success) {
if ($success) {
$data{$hash->{TYPE}}{$name}{$cachename} = decode_json ($json);
Log3 ($name, 3, qq{$name - cached data "$cachename" restored});
Log3 ($name, 3, qq{$name - cached data "$title" restored});
}
else {
Log3 ($name, 1, qq{$name - WARNING - The content of file "$file" is not readable and may be corrupt});
Log3 ($name, 1, qq{$name - WARNING - The content of file "$file" is not readable or may be corrupt});
}
}
@ -1111,8 +1121,9 @@ sub Set {
return if((controller($name))[1]);
my ($setlist,@fcdevs,@cfs,@condevs);
my ($setlist,@fcdevs,@cfs,@condevs,@bkps);
my ($fcd,$ind,$med,$cf,$sp,$coms) = ('','','','','','');
my $type = $hash->{TYPE};
my @re = qw( aiData
batteryTriggerSet
@ -1138,6 +1149,7 @@ sub Set {
push @fcdevs, 'SolCast-API';
push @fcdevs, 'ForecastSolar-API';
push @fcdevs, 'VictronKI-API';
my $rdd = join ",", @fcdevs;
for my $h (@chours) {
@ -1145,15 +1157,25 @@ sub Set {
}
$cf = join " ", @cfs;
my $type = $hash->{TYPE};
for my $c (sort{$a<=>$b} keys %{$data{$type}{$name}{consumers}}) {
push @condevs, $c if($c);
}
$coms = @condevs ? join ",", @condevs : 'noArg';
$coms = @condevs ? join ",", @condevs : 'noArg';
my $ipai = isPrepared4AI ($hash);
opendir (DIR, $cachedir);
while (my $file = readdir (DIR)) {
next unless (-f "$cachedir/$file");
next unless ($file =~ /_${name}_/);
next unless ($file =~ /_\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}$/);
push @bkps, 'recover-'.$file;
}
closedir (DIR);
my $rf = @bkps ? ','.join ",", reverse sort @bkps : '';
## allg. gültige Setter
#########################
$setlist = "Unknown argument $opt, choose one of ".
@ -1167,12 +1189,12 @@ sub Set {
"energyH4Trigger:textField-long ".
"inverterStrings ".
"modulePeakString ".
"operatingMemory:backup,save".$rf." ".
"operationMode:active,inactive ".
"plantConfiguration:check,save,restore ".
"powerTrigger:textField-long ".
"pvCorrectionFactor_Auto:noLearning,on_simple".($ipai ? ',on_simple_ai,' : ',')."on_complex".($ipai ? ',on_complex_ai,' : ',')."off ".
"reset:$resets ".
"writeHistory:noArg ".
$cf." "
;
@ -1848,7 +1870,7 @@ sub _setplantConfiguration { ## no critic "not used"
$arg = 'check' if (!$arg);
if($arg eq "check") {
if ($arg eq "check") {
my $out = checkPlantConfig ($hash);
$out = qq{<html>$out</html>};
@ -1861,9 +1883,9 @@ sub _setplantConfiguration { ## no critic "not used"
return $out;
}
if($arg eq "save") {
$err = writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben
if($err) {
if ($arg eq "save") {
$err = writeCacheToFile ($hash, 'plantconfig', $plantcfg.$name); # Anlagenkonfiguration File schreiben
if ($err) {
return $err;
}
else {
@ -1871,11 +1893,12 @@ sub _setplantConfiguration { ## no critic "not used"
}
}
if($arg eq "restore") {
if ($arg eq "restore") {
($err, @pvconf) = FileRead ($plantcfg.$name);
if(!$err) {
if (!$err) {
my $rbit = 0;
for my $elem (@pvconf) {
my ($reading, $val) = split "<>", $elem;
next if(!$reading || !defined $val);
@ -1883,7 +1906,7 @@ sub _setplantConfiguration { ## no critic "not used"
$rbit = 1;
}
if($rbit) {
if ($rbit) {
return qq{Plant Configuration restored from file "}.$plantcfg.$name.qq{"};
}
else {
@ -2237,19 +2260,47 @@ return;
}
################################################################
# Setter writeHistory
# Setter operatingMemory
# (Ersatz für Setter writeHistory)
################################################################
sub _setwriteHistory { ## no critic "not used"
sub _setoperatingMemory { ## no critic "not used"
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $prop = $paref->{prop} // return qq{no operation specified for command};
my $ret = writeCacheToFile ($hash, "circular", $pvccache.$name); # Cache File für PV Circular schreiben
return $ret if($ret);
if ($prop eq 'save') {
periodicWriteCachefiles ($hash); # Cache File für PV History, PV Circular schreiben
}
$ret = writeCacheToFile ($hash, "pvhist", $pvhcache.$name); # Cache File für PV History schreiben
if ($prop eq 'backup') {
periodicWriteCachefiles ($hash, 'bckp'); # Backup Files erstellen und alte Versionen löschen
}
return $ret;
if ($prop =~ /^recover-/xs) { # Sicherung wiederherstellen
my $file = (split "-", $prop)[1];
Log3 ($name, 3, "$name - recover saved cache file: $file");
if ($file =~ /^PVH_/xs) { # Cache File PV History einlesen
$paref->{cachename} = 'pvhist';
$paref->{title} = 'pvHistory';
}
if ($file =~ /^PVC_/xs) { # Cache File PV Circular einlesen
$paref->{cachename} = 'circular';
$paref->{title} = 'pvCircular';
}
$paref->{file} = "$cachedir/$file";
_readCacheFile ($paref);
delete $paref->{file};
delete $paref->{cachename};
delete $paref->{title};
}
return;
}
################################################################
@ -2276,7 +2327,7 @@ sub _setclientAction { ## no critic "not used"
my $cname = shift @args; # Consumername
my $tail = join " ", map { my $p = $_; $p =~ s/\s//xg; $p; } @args; ## no critic 'Map blocks' # restliche Befehlsargumente
Log3($name, 4, qq{$name - Client Action received / execute: "$action $cname $tail"});
Log3 ($name, 4, qq{$name - Client Action received / execute: "$action $cname $tail"});
if($action eq 'set') {
CommandSet (undef, "$cname $tail");
@ -4700,9 +4751,12 @@ sub deleteOldBckpFiles {
my $max = int @files - $dfk;
for (my $i = 0; $i < $max; $i++) {
unlink "$cachedir/$files[$i]";
my $done = 1;
unlink "$cachedir/$files[$i]" or do { Log3 ($name, 1, "$name - WARNING - Could not delete '$cachedir/$files[$i]': $!");
$done = 0;
};
Log3 ($name, 3, "$name - old backup file '$cachedir/$files[$i]' deleted");
Log3 ($name, 3, "$name - old backup file '$cachedir/$files[$i]' deleted") if($done);
}
return;
@ -12073,7 +12127,8 @@ sub finishTrain {
name => $name,
type => $type,
file => $aitrained.$name,
cachename => 'aitrained'
cachename => 'aitrained',
title => 'aiTrainedData'
}
);
}
@ -16132,6 +16187,33 @@ to ensure that the system configuration is correct.
</ul>
<br>
<ul>
<a id="SolarForecast-set-operatingMemory"></a>
<li><b>operatingMemory backup | save | recover-&lt;File&gt; </b> <br><br>
The pvHistory (PVH) and pvCircular (PVC) components of the internal cache database are stored in the file system. <br>
The target directory is "../FHEM/FhemUtils". This process is carried out regularly by the module in the background. <br><br>
<ul>
<table>
<colgroup> <col width="17%"> <col width="83%"> </colgroup>
<tr><td> <b>backup</b> </td><td>Saves the active in-memory structures with the current timestamp. </td></tr>
<tr><td> </td><td><a href="#SolarForecast-attr-ctrlBackupFilesKeep">ctrlBackupFilesKeep</a> generations of the files are saved. Older versions are deleted. </td></tr>
<tr><td> </td><td>Files: PVH_SolarForecast_&lt;name&gt;_&lt;Timestamp&gt;, PVC_SolarForecast_&lt;name&gt;_&lt;Timestamp&gt; </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>save</b> </td><td>The active in-memory structures are saved. </td></tr>
<tr><td> </td><td>Files: PVH_SolarForecast_&lt;name&gt;, PVC_SolarForecast_&lt;name&gt; </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>recover-&lt;File&gt;</b> </td><td>Restores the data of the selected backup file as an active in-memory structure. </td></tr>
<tr><td> </td><td>To avoid inconsistencies, the PVH.* and PVC.* files should be restored in pairs </td></tr>
<tr><td> </td><td>with the same time stamp. </td></tr>
</table>
</ul>
<br>
</ul>
</li>
<br>
<ul>
<a id="SolarForecast-set-operationMode"></a>
<li><b>operationMode </b> <br><br>
@ -16379,17 +16461,6 @@ to ensure that the system configuration is correct.
</ul>
<br>
<ul>
<a id="SolarForecast-set-writeHistory"></a>
<li><b>writeHistory </b> <br><br>
The internal cache database is stored in the file system. By default, this process is
regularly in the background. In the internal "LCACHEFILE", the last file written and the time
of the last storage is documented. <br>
</li>
</ul>
<br>
</ul>
<br>
@ -16987,8 +17058,16 @@ to ensure that the system configuration is correct.
</li>
<br>
<a id="SolarForecast-attr-ctrlBackupFilesKeep"></a>
<li><b>ctrlBackupFilesKeep</b><br>
Defines the number of generations of backup files
(see also <a href="#SolarForecast-set-operatingMemory">set &lt;name&gt; operatingMemory backup</a>). <br>
(default: 3)
</li>
<br>
<a id="SolarForecast-attr-ctrlBatSocManagement"></a>
<li><b>ctrlBatSocManagement lowSoc=&lt;Value&gt; upSoC=&lt;Value&gt; [maxSoC=&lt;Value&gt;] [careCycle=&lt;Value&gt;] </b><br>
<li><b>ctrlBatSocManagement lowSoc=&lt;Value&gt; upSoC=&lt;Value&gt; [maxSoC=&lt;Value&gt;] [careCycle=&lt;Value&gt;] </b> <br><br>
If a battery device (currentBatteryDev) is installed, this attribute activates the battery SoC management. <br>
The <b>Battery_OptimumTargetSoC</b> reading contains the optimum minimum SoC calculated by the module. <br>
The <b>Battery_ChargeRequest</b> reading is set to '1' if the current SoC has fallen below the minimum SoC. <br>
@ -18184,6 +18263,33 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</ul>
<br>
<ul>
<a id="SolarForecast-set-operatingMemory"></a>
<li><b>operatingMemory backup | save | recover-&lt;Datei&gt; </b> <br><br>
Die Komponenten pvHistory (PVH) und pvCircular (PVC) der internen Cache Datenbank werden im Filesystem gespeichert. <br>
Das Zielverzeichnis ist "../FHEM/FhemUtils". Dieser Vorgang wird vom Modul regelmäßig im Hintergrund ausgeführt. <br><br>
<ul>
<table>
<colgroup> <col width="17%"> <col width="83%"> </colgroup>
<tr><td> <b>backup</b> </td><td>Sichert die aktiven In-Memory Strukturen mit dem aktuellen Zeitstempel. </td></tr>
<tr><td> </td><td>Es werden <a href="#SolarForecast-attr-ctrlBackupFilesKeep">ctrlBackupFilesKeep</a> Generationen der Dateien gespeichert. Ältere Versionen werden gelöscht. </td></tr>
<tr><td> </td><td>Dateien: PVH_SolarForecast_&lt;name&gt;_&lt;Zeitstempel&gt;, PVC_SolarForecast_&lt;name&gt;_&lt;Zeitstempel&gt; </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>save</b> </td><td>Die aktiven In-Memory Strukturen werden gespeichert. </td></tr>
<tr><td> </td><td>Dateien: PVH_SolarForecast_&lt;name&gt;, PVC_SolarForecast_&lt;name&gt; </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>recover-&lt;Datei&gt;</b> </td><td>Stellt die Daten der ausgewählten Sicherungsdatei als aktive In-Memory Struktur wieder her. </td></tr>
<tr><td> </td><td>Um Inkonsistenzen zu vermeiden, sollten die Dateien PVH.* und PVC.* mit dem gleichen </td></tr>
<tr><td> </td><td>Zeitstempel paarweise recovert werden. </td></tr>
</table>
</ul>
<br>
</ul>
</li>
<br>
<ul>
<a id="SolarForecast-set-operationMode"></a>
<li><b>operationMode </b> <br><br>
@ -18438,17 +18544,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</ul>
<br>
<ul>
<a id="SolarForecast-set-writeHistory"></a>
<li><b>writeHistory </b> <br><br>
Die interne Cache Datenbank wird im Filesystem gespeichert. Dieser Vorgang wird per default
regelmäßig im Hintergrund ausgeführt. Im Internal "LCACHEFILE" wird die letzte geschriebene Datei und der Zeitpunkt
der letzten Speicherung dokumentiert. <br>
</li>
</ul>
<br>
</ul>
<br>
@ -19046,8 +19141,16 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</li>
<br>
<a id="SolarForecast-attr-ctrlBackupFilesKeep"></a>
<li><b>ctrlBackupFilesKeep</b><br>
Legt die Anzahl der Generationen von Sicherungsdateien
(siehe <a href="#SolarForecast-set-operatingMemory">set &lt;name&gt; operatingMemory backup</a>) fest. <br>
(default: 3)
</li>
<br>
<a id="SolarForecast-attr-ctrlBatSocManagement"></a>
<li><b>ctrlBatSocManagement lowSoc=&lt;Wert&gt; upSoC=&lt;Wert&gt; [maxSoC=&lt;Wert&gt;] [careCycle=&lt;Wert&gt;] </b><br>
<li><b>ctrlBatSocManagement lowSoc=&lt;Wert&gt; upSoC=&lt;Wert&gt; [maxSoC=&lt;Wert&gt;] [careCycle=&lt;Wert&gt;] </b> <br><br>
Sofern ein Batterie Device (currentBatteryDev) installiert ist, aktiviert dieses Attribut das Batterie
SoC-Management. <br>
Das Reading <b>Battery_OptimumTargetSoC</b> enthält den vom Modul berechneten optimalen Mindest-SoC. <br>