Hauptmenü

Neueste Beiträge

#1
SVG / Plots / logProxy / Ergänzungen zu plotAsPng und F...
Letzter Beitrag von Prof. Dr. Peter Henning - 21 September 2026, 12:34:12
Hallo Rudi,

hier meine Vorschläge.

1. in Zeile 2029 ist by x= ... ein "'" zuviel. Statt
SVG_pO sprintf("<rect x='%d'' y='%d' width='%d' height='%d' $attr/>",muss es heißen
SVG_pO sprintf("<rect x='%d' y='%d' width='%d' height='%d' $attr/>",
2.Die beim Zeichnen von Symbolen verwendete sprintf-Funktion wirft eine Warnungsmeldung
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,
$attr wird dann als weiterer Parameter übergeben. Also ab Zeile 2007
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
      );
    }
  }
}

3. Die Funktion plotAsPng macht etwas Schwierigkeiten, die in der libRSVG-library begründet liegen.
a.) Sie kommt mit CSS-Variablen nicht zurecht. Diese sind aber in CSS-Files sehr praktisch, weil man damit in CSS-Dateien den Wartungsaufwand drastisch verringert. Beispielsweise müssen Farben nur einmal angegeben werden und können dann referenziert werden
 
  --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); }

b.) Sie ignoriert die Festlegung von Schriftfamilie und Schriftgröße.

c.) Die erzeugten PNG-Dateien sind nicht skalierbar, sondern haben die durch das FHEM-Attribut plotsize festgelegte Größe.

Zur Behebung dieser drei Schwächen muss man zunächst die erzeugte SVG-Datei bearbeiten, dafür gibt es drei neue Helperfunktionen
##################
# 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/&/&amp;/g;
    $fontFamily =~ s/"/&quot;/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
    );
  }

Die gewünschte Zielbreite der PNG-Datei wird einfach als 4. Parameter an plotAsPng übergeben.

Und schließlich habe ich noch eine weitere Helperfunktion, die eigentlich das Ziel der ganzen Sache war. Dieser gebe ich als ersten Parameter den Namen eines FHEM SVG-Device, als zweiten Parameter den Namen der PNG-Datei, und als dritten Parameter die horizontale Auflösung in Pixeln.
###############################################################################
#
#  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;
}

Ob man das auch als Ausgabeoption in 98_SVG.pm einbaut, lasse ich offen.

Die komplett geänderte 98_SVG.pm hänge ich zum Testen an. Achtung: Diese Datei enthält in plotAsPng noch einen überflüssigen Block, der mir die komplett erzeugte SVG nach /tmp geschrieben hat.

LG

pah

P.S.: Bevor jemand fragt, warum ich das nicht als Patchdatei liefere: Code-Review...


#2
TabletUI / Aw: Darstellung Sonnenbatterie
Letzter Beitrag von mr_petz - 21 September 2026, 11:53:08
okay gemerged.
entschuldigung für die späte rückmeldung
#3
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von enno - 21 September 2026, 11:23:47
Moin,

ich bekomme stündlich folgende Warnung: 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)

Für die Suche habe ich mir an der Stelle ein Log eingebaut. Das sagt mir: 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?

Gruss
  Enno
#4
Solaranlagen / Aw: [36_Senec.pm] FHEM module ...
Letzter Beitrag von Uwe Ernst - 21 September 2026, 11:02:32
Hallo curiosus
Dein neues Modul läuft bei mir Fehlerfrei. Habe aber die API Abfrage auf 15 min. geändert.

HGButte
Ich mache die Abfrage der Aktuellen Werte mit HTTPMOD:
Abfrage alle 5 sec.
Nur wenn schnellere Abfrage erfordrlich sind (Heizstab in Pufferspeicher ein) schalte ich auf 2 sec. durch at und notify um.
Bisher keine Probleme.
#5
FRITZ!Box / Aw: FritzSmart mit Fritz Labor...
Letzter Beitrag von roelleke - 21 September 2026, 10:22:30
Hallo,
ich habe die Version von dem obigen Link ausprobiert, aber sie führt zu dem gleichen Fehler. Die alte Version '31628 2026-09-07 13:16:46Z' funktioniert hingegen einwandfrei.

Gruß Dieter
#6
Sonstiges / Aw: MQTT best current practice
Letzter Beitrag von rudolfkoenig - 21 September 2026, 09:36:36
ZitatWie entsteht das  Array neu?
In computeClientArray, aufgerufen in Dispatch.
#7
FHEM Code changes / Revision 31671: controls_fhem....
Letzter Beitrag von System - 21 September 2026, 08:40:45
Revision 31671: controls_fhem.txt: fhemupdate checkin

controls_fhem.txt: fhemupdate checkin

Source: Revision 31671: controls_fhem.txt: fhemupdate checkin
#8
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 21 September 2026, 07:53:15
Moin,

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.
Also warten wir mal ab ob es schon der Weisheit letzter Schluß ist. Auch andere Module können noch problematische Speicher-Situationen hervorrufen.

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.
 
#9
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von TheTrumpeter - 21 September 2026, 06:58:46
Zitat von: DS_Starter am 20 September 2026, 22:36:11Speicherleck bei Verwendung von AI::FANN
Aja... 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.

Ein 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. In den Sommermonaten komme ich typischerweise mit dem Mindestwert von 1 kW durch. In diesen Monaten könnte selbst eine kleine Batterie auch den Nachtverbrauch problemlos decken, sodass keinerlei Eingriffe nötig wären. Gleichzeitig sollte selbst an "schlechten" Tagen tagsüber immer wieder bisschen nachgeladen werden können, sodass auch etwaige Bezugsphasen am Tag damit kompensiert werden könnten.
Im Winter könnte es aber sinnvoll sein, die Batterie nachts mit geringer Leistung vom Netz zu laden, um tagsüber Spitzen zu glätten und so von 4-5 kW Netzbezugsentgelt auf 2 kW runterzukommen.
Natürlich lohnt es sich nicht eine Batterie nur deshalb anzuschaffen, aber - falls ich sie anschaffe - wäre das ein zusätzlicher sinnvoller Anwendungsfall.
#10
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 20 September 2026, 22:36:11
@all,

ich habe soben die V 2.10.4 eingecheckt.
Möglicherweise habe ich ein potentielles Speicherleck bei Verwendung von AI::FANN entdeckt und beseitigt.

Morgen wie gewöhnlich im Update enthalten.