SVG_pO sprintf("<rect x='%d'' y='%d' width='%d' height='%d' $attr/>",muss es heißenSVG_pO sprintf("<rect x='%d' y='%d' width='%d' height='%d' $attr/>",Zitat2026.09.21 11:45:09 1: PERL WARNING: Invalid conversion in sprintf: "%"" at /opt/fhem/FHEM/98_SVG.pm line 2061.(bzw. mit anderen Zeilennummern, wenn das Symbol kein Diamond ist) aus, wenn in einem Label des Plots ein "%"-Zeichen auftaucht, und dieses Label dann in der Legende verwendet wird. Die Darstellung ist zwar korrekt, aber die Warnungsmeldung müsste nicht sein. Dazu muss bei den Symbolen (außer circle) das $attr aus dem ersten Argument sprintf herausgenommen werden und durch ein "%s" ersetzt werden,
if ($lType =~ /^points(:([a-z]+))?(:([\d.]+))?/) {
my $pShape = $2 ? $2 : "di";
my $pSize = $4;
if(!$pSize) { # if not defined, use the line-width as size
$attributes =~ s/stroke-width:(\d+)/stroke-width:1/;
$pSize = $1 && $1 >= 2 ? $1 : 3;
}
foreach my $i (0..int(@{$dxp})-1) {
my ($x1, $y1) = (int($x+$dxp->[$i]),
int($y+$h-($dyp->[$i]-$min)*$hmul));
next if($x1 == $lx && $y1 == $ly);
$lx = $x1; $ly = $y1;
my $attr = "$attributes $lStyle".($isFill ? "" : ' fill="none"');
if ($pShape eq "circle") {
SVG_pO "<circle cx='$x1' cy='$y1' r='$pSize' $attr/>";
} elsif ($pShape eq "square") {
my $d = $pSize * 2;
SVG_pO sprintf(
"<rect x='%d' y='%d' width='%d' height='%d' %s/>",
$x1-$pSize, $y1-$pSize, $d, $d, $attr
);
} elsif ($pShape eq "triangleup") {
SVG_pO sprintf(
"<polygon points='%d,%d %d,%d %d,%d' %s/>",
$x1, $y1-$pSize,
$x1-$pSize, $y1+$pSize,
$x1+$pSize, $y1+$pSize,
$attr
);
} elsif ($pShape eq "triangledown") {
SVG_pO sprintf(
"<polygon points='%d,%d %d,%d %d,%d' %s/>",
$x1-$pSize, $y1-$pSize,
$x1+$pSize, $y1-$pSize,
$x1, $y1+$pSize,
$attr
);
} elsif ($pShape eq "plus") {
SVG_pO sprintf(
"<line x1='%d' y1='%d' x2='%d' y2='%d' %s/>",
$x1-$pSize, $y1, $x1+$pSize, $y1, $attr
);
SVG_pO sprintf(
"<line x1='%d' y1='%d' x2='%d' y2='%d' %s/>",
$x1, $y1-$pSize, $x1, $y1+$pSize, $attr
);
} elsif ($pShape eq "cross") {
SVG_pO sprintf(
"<line x1='%d' y1='%d' x2='%d' y2='%d' %s/>",
$x1-$pSize, $y1-$pSize,
$x1+$pSize, $y1+$pSize,
$attr
);
SVG_pO sprintf(
"<line x1='%d' y1='%d' x2='%d' y2='%d' %s/>",
$x1+$pSize, $y1-$pSize,
$x1-$pSize, $y1+$pSize,
$attr
);
} elsif ($pShape eq "minus") {
SVG_pO sprintf(
"<line x1='%d' y1='%d' x2='%d' y2='%d' %s/>",
$x1-$pSize, $y1, $x1+$pSize, $y1, $attr
);
} else { # diamond
SVG_pO sprintf(
"<polygon points='%d,%d %d,%d %d,%d %d,%d %d,%d' %s/>",
$x1-$pSize, $y1,
$x1, $y1-$pSize,
$x1+$pSize, $y1,
$x1, $y1+$pSize,
$x1-$pSize, $y1,
$attr
);
}
}
}
--svg-l0: red;
--svg-l1: green;
--svg-l2: blue;
.SVGplot.l0 { stroke: var(--svg-l0); }
.SVGplot.l1 { stroke: var(--svg-l1); }
.SVGplot.l2 { stroke: var(--svg-l2); }
##################
# Helper function to replace CSS Vars
sub SVG_resolveCssVars($) {
my ($svg) = @_;
my %vars;
# CSS Custom Properties aus :root lesen
if($svg =~ /:root\s*\{(.*?)\}/s) {
my $root = $1;
while($root =~ /--([\w-]+)\s*:\s*([^;]+)\s*;/g) {
$vars{$1} = $2;
}
}
# var(--name) durch den gefundenen Wert ersetzen
$svg =~ s{
var\(--([\w-]+)\)
}{
exists($vars{$1}) ? $vars{$1} : "var(--$1)"
}gex;
return $svg;
}
##################
# Helper function to fix SVG fonts
sub SVG_fixLibRSVGFonts($) {
my ($svg) = @_;
my $fontFamily;
if($svg =~ /(?:^|\})\s*text\s*\{([^}]*)\}/s) {
my $css = $1;
if($css =~ /font-family\s*:\s*([^;!]+)(?:\s*!important)?\s*;/i) {
$fontFamily = $1;
$fontFamily =~ s/^\s+|\s+$//g;
}
}
return $svg if(!defined($fontFamily) || $fontFamily eq "");
# XML-Attribut sicher quoten
$fontFamily =~ s/&/&/g;
$fontFamily =~ s/"/"/g;
$svg =~ s{
<text\b
}{
qq{<text font-family="$fontFamily"}
}gex;
return $svg;
}
##################
# Helper function to scale SVG
sub SVG_scaleForLibRSVG($$$) {
my ($svg, $newWidth, $newHeight) = @_;
return $svg
if($svg !~ /<svg\b[^>]*\bwidth=['"]([\d.]+)(?:px)?['"][^>]*\bheight=['"]([\d.]+)(?:px)?['"]/s);
my ($oldWidth, $oldHeight) = ($1, $2);
$svg =~ s{<svg\b([^>]*)>}{
my $attr = $1;
$attr =~ s/\bwidth=['"][^'"]+['"]/width="${newWidth}px"/;
$attr =~ s/\bheight=['"][^'"]+['"]/height="${newHeight}px"/;
$attr =~ s/\s+viewBox=['"][^'"]*['"]//;
$attr =~ s/width\s*:\s*[\d.]+px/width:${newWidth}px/;
$attr =~ s/height\s*:\s*[\d.]+px/height:${newHeight}px/;
qq{<svg$attr viewBox="0 0 $oldWidth $oldHeight">};
}ex;
return $svg;
}
In der Funktion plotAsPng werden diese drei Helperfunktionen gerufen, bevor die SVG-Datei an die libRSVG übergeben wird. Nach "($mimetype, $svgdata) = SVG_showLog("unused");" wird also der Code geändert zu
my ($w, $h) = split(",", AttrVal($svgName, "plotsize", "800,160"));
$svgdata =~ s/<\/svg>/<polyline opacity="0" points="0,0 $w,$h"\/><\/svg>/;
# Forum #32791,#116138: some lib versions cannot parse complex CSS selectors
$svgdata =~ s/\.SVGplot\./\./g if(AttrVal($svgName, "plotAsPngFix", 0));
$svgdata = Encode::decode("UTF-8", $svgdata) if(!$unicodeEncoding); #129693
#-- CSS Custom Properties fuer LibRSVG aufloesen
$svgdata = SVG_resolveCssVars($svgdata);
#-- Fix fonts
$svgdata = SVG_fixLibRSVGFonts($svgdata);
#-- target width as fourth parameter for output as png
my $targetWidth = $plotName[3];
if($targetWidth) {
my $targetHeight = int($h * $targetWidth / $w + 0.5);
$svgdata = SVG_scaleForLibRSVG(
$svgdata,
$targetWidth,
$targetHeight
);
}###############################################################################
#
# plot2png
#
###############################################################################
sub plot2png($$$) {
my ($plot, $file, $width) = @_;
my $png = plotAsPng($plot, undef, undef, $width);
return "plotAsPng failed" if(!defined($png));
open(my $fh, ">", $file)
or return "Cannot write $file: $!";
binmode($fh);
print $fh $png;
close($fh);
return $file;
}PERL WARNING: Use of uninitialized value in string ne at fhem.pl line 5140.
2026.09.21 11:00:05.101 1: stacktrace:
2026.09.21 11:00:05.101 1: main::__ANON__ called by fhem.pl (5140)
2026.09.21 11:00:05.102 1: main::readingsBulkUpdate called by ./FHEM/76_SolarForecast.pm (36313)
2026.09.21 11:00:05.102 1: FHEM::SolarForecast::_createReadingsFromArrayFast called by ./FHEM/76_SolarForecast.pm (12788)
2026.09.21 11:00:05.102 1: FHEM::SolarForecast::__ANON__ called by ./FHEM/76_SolarForecast.pm (12828)
2026.09.21 11:00:05.102 1: FHEM::SolarForecast::_ctStepTiming called by ./FHEM/76_SolarForecast.pm (12788)
2026.09.21 11:00:05.102 1: FHEM::SolarForecast::centralTask called by ./FHEM/76_SolarForecast.pm (12499)
2026.09.21 11:00:05.102 1: FHEM::SolarForecast::runTask called by fhem.pl (4012)
2026.09.21 11:00:05.102 1: main::CallFn called by fhem.pl (855)SolarForecast DEBUG bulkUpdate: reading=[pvCorrectionFactor_11] new=[0.96 (automatic - old factor: 0.77, AI result used, Sun Alt range: 30, Cloud range: 75, Days in range: 4)] old=<undef> elem=[pvCorrectionFactor_11<>0.96 (automatic - old factor: 0.77, AI result used, Sun Alt range: 30, Cloud range: 75, Days in range: 4)] Die Warnung kommt wohl vom fehlenden old=<undef>. Was kann ich tun, um das gerade zu ziehen?ZitatWie entsteht das Array neu?In computeClientArray, aufgerufen in Dispatch.
ZitatAja... beobachte schon länger stetig steigenden Speicherverbrauch.Kann aber auch noch andere Ursachen als SF AI::FANN haben. Gestern hatte ich z.B. noch ein potentielles Speicherleck im FHEM Kern selbst kommuniziert.
ZitatEin Anteil meiner Netzentgelte ist abhängig von der Peak-Leistung des Netzbezugs, d.h. für das laufende Monat wird der höchste 15-min-Wert als Basis verwendet....Danke für die Erläuterung. Jetzt habe den Sinn des Anliegens besser verstande, denke ich.
Zitat von: DS_Starter am 20 September 2026, 22:36:11Speicherleck bei Verwendung von AI::FANNAja... beobachte schon länger stetig steigenden Speicherverbrauch.
Zitat von: DS_Starter am 18 September 2026, 21:01:06Was den Momentanbezug angeht ... meine Batterieanlage funktioniert generell so, dass genau der benötigte Momentan-Netzbezug durch die Bat-Entladung kompensiert wird bis auf einen kleinen Restbetrag. Dazu bedarf es keiner besonderen Konfiguration oder Steuerung, sondern ist Bestandteil der grundlegenden Funktion des ESS. Die Bat entlädt so lange bis der eingestellte optimal SoC oder lowSoC erreicht ist.Natürlich. Darum geht es mir wie gesagt auch gar nicht.