FTUI3 Widget Bar

Aus FHEMWiki
Version vom 4. Juni 2025, 19:18 Uhr von Pahenning (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Auf dieser Seite wird erläutert, wie man in FTUI3 die grafische Anzeige eines Readings eines FHEM-Devices in Form eines horizontalen Balkens mit rundem Querschnitt erstellen kann.

Diese Widgets wurden zuerst 2019 für das FHEM Tablet UI V2 erstellt, siehe FTUI Widget Bar.

Installation

Zunächst muss eine Grafikdatei im Format SVG (Scalable Vector Graphics) erstellt werden, hier mit dem Namen widget_bar.svg und dem Inhalt

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="0 0 300 20" width="200px" height="150px">
        <!-- ++++++++++++++++++++++++++++++++++++ Bar Widget ++++++++++++++++++++++++++++++++++++++ -->
        <g id="bar{{suffix}}">
            <g transform="translate(0,0)">
                <rect x="24" y="5" width="40" height="80" rx="20" ry="40" fill="url(grad0)"/>
                <rect x="252" y="5" width="40" height="80" rx="20" ry="40" fill="rgb(250,250,250)"/>
                <rect id="side{{suffix}}" x="24" y="5" width="40" height="80" rx="20" ry="40" fill="{{fillside}}"/>
                <rect id="top{{suffix}}" x="24" y="5" width="40" height="80" rx="20" ry="40" fill="{{filltop}}"/>
                <rect x="252" y="5" width="40" height="80" rx="20" ry="40" fill="none"
                    stroke="rgb(139, 137, 137)" stroke-width="2"/>
                <rect id="topline{{suffix}}" x="24" y="5" width="40" height="80" rx="20" ry="40" fill="none"
                    stroke="rgb(139, 137, 137)" stroke-width="2"/>
                <rect x="24" y="5" width="268" height="80" rx="20" ry="40" fill="none"
                    stroke="rgb(139, 137, 137)" stroke-width="2"/>
                <text id="label{{suffix}}" x="28" y="52" fill="rgb(75, 75, 75)"
                    style="font-family:Helvetica;font-size:24px;font-weight:bold;"/>
            </g>
        </g>
</svg>

Darin sind die Parameter suffix, fillside und filltop enthalten. Diese Parameter werden gesetzt, indem die SVG-Datei an beliebiger Stelle und beliebig oft in eine FTUI3-Seite eingebunden wird, z.B. mit

<ftui-content suffix="<SUFFIX>" file="widget_bar.svg" fillside="<FARBE1>" filltop="<FARBE2>"> 
  </ftui-content>
  • Der String SUFFIX wird durch FTUI3 in die aufgerufene Datei eingesetzt. Wichtig: Für jeden anzuzeigenden Balken muss es einen eigenen (und eindeutigen) suffix geben, da dieser verwendet wird, um die Identifier der SVG-Elemente zu setzen.
  • FARBE1 und FARBE2 sind SVG-Farbspezifikationen, z.B. können diese sich auf vordefinierte Gradienten beziehen.

Desweiteren muss im Header der FTUI-Seite etwas JavaScript-Code eingebunden werden.

<script>
const ftui_updatebar = (max,unit,suffix) => input => updatebar(input,max,unit,suffix);
    ...
function updatebar(val,max,unit,suffix) {
    if (! val) return 'updatebar has empty value argument'; 
    if (! max || max == 0) return 'updatebar has missing or zero scale factor'; 
    var val1 = Math.floor(val / max * 228 + 24);
    var style;
    var textpos;
    if (val1 > 148) {
        textpos = 28;
        style = "text-anchor:start;font-family:Helvetica;font-size:30px;font-weight:bold";
    } else {
        textpos = 252;
        style = "text-anchor:end;font-family:Helvetica;font-size:30px;font-weight:bold";
    }
    document.getElementById("side"+suffix).setAttribute("width", val1 + 16);
    document.getElementById("top"+suffix).setAttribute("x", val1);
    document.getElementById("topline"+suffix).setAttribute("x", val1);
    document.getElementById("label"+suffix).textContent = val + " " + unit;
    document.getElementById("label"+suffix).setAttribute("x", textpos);
    document.getElementById("label"+suffix).setAttribute("style", style);
} 

Schließlich muss noch an beliebiger Stelle auf der FTUI3-Seite dafür gesorgt werden, dass das Diagramm auch mit Werten aus FHEM befüllt wird. Das geschieht am Einfachsten durch ein <ftui-label>-Element

 <ftui-label [text]="DEVICE:READING | ftui_updatebar(<MAXIMALWERT>,'<EINHEIT>','<SUFFIX>')" class="hidden">
        </ftui-label>
  • Das Reading <READING> enthält eine Zahl
  • Der Maximalwert <MAX> ist der Wert, bei welchem der Balken komplett gefüllt erscheint.
  • Der String <EINHEIT> gibt eine Einheit an.
  • Der String <SUFFIX> muss denselben Wert haben, wie bei dem eingebundenen Content-File

Anwendungsbeispiel

Gaswasser 2025.png

Auf einer FTUI-Seite werden Anzeigen für den Gas- und Wasserverbrauch benötigt. Die Daten stehen in verschiedenen Readings des FHEM-Device gaswaterProfileC

 <!--Gas -->
      <div style="position:absolute;left:230px;top:0px;color:blue">
        <ftui-label [text]="gaswaterProfileC:GV.P | fix(1)" size="35px"
          style="font-family:Helvetica;font-weight:bold;">
          <span slot="unit" class="size--2">m³/h</span>
        </ftui-label>
        <ftui-label [text]="gaswaterProfileC:GV.E | ftui_updatebar(20,'m³','g')" class="hidden">
        </ftui-label></div>
      <div style="position:absolute;left:200px;top:-30px;width:200px;height:150px">
        <ftui-content suffix="g" file="widget_bar.svg" fillside="url(#grad1p)" filltop="url(#grad2p)"> 
        </ftui-content>
      </div>
      <div style="position:absolute;left:230px;top:95px">
        <ftui-label text="Gas" size="14px" style="font-family:Helvetica;font-weight:bold;"></ftui-label>
      </div>
      <!--Water -->
      <div style="position:absolute;left:230px;top:130px;color:blue">
        <ftui-label [text]="gaswaterProfileC:WV.F | fix(1)" size="35px"
          style="font-family:Helvetica;font-weight:bold;">
          <span slot="unit" class="size--2">l/h</span>
        </ftui-label>
        <ftui-label [text]="gaswaterProfileC:WV.V | ftui_updatebar(500,'l','w')" class="hidden"></ftui-label>
      </div>
      <div style="position:absolute;left:200px;top:100px;width:200px;height:150px">
        <ftui-content suffix="w" file="widget_bar.svg" fillside="url(#grad1b)" filltop="url(#grad2b)"> 
        </ftui-content>
      </div>     
      <div style="position:absolute;left:230px;top:225px">
        <ftui-label text="Wasser" size="14px" style="font-family:Helvetica;font-weight:bold;"></ftui-label>
      </div>

Die Farbspezifkationen seien der Vollständigkeit halber auch angegeben:

  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
      viewBox="0 0 0 0" width="0px" height="0px">
      <defs>
        <!-- white-snowwhite -->
        <linearGradient id="grad0" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:white;stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb(139, 137, 137);stop-opacity:1"/>
        </linearGradient>
        <!-- lightsalmon/red and lightsalmon/lightsalmon3 -->
        <linearGradient id="grad1r" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 192, 188);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:red;stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2r" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 192, 188);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 255, 140, 105);stop-opacity:1"/>
        </linearGradient>
        <!-- LightGoldenrod1/DarkOrange and LightGoldenrod1/DarkGoldenrod3 -->
        <linearGradient id="grad1o" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 236, 139);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 205, 149, 12);stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2o" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 236, 139);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 205, 149, 12);stop-opacity:1"/>
        </linearGradient>
        <!-- pink/deeppink and pink/hotpink3 -->
        <linearGradient id="grad1p" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 192, 203);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 255, 20, 147);stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2p" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 255, 192, 203);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 205, 96, 144);stop-opacity:1"/>
        </linearGradient>
        <!-- chartreuse/green and chartreuse/chartreuse3  -->
        <linearGradient id="grad1g" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 127,255, 0);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:green;stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2g" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb( 127,255, 0);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 102, 205, 0);stop-opacity:1"/>
        </linearGradient>
        <!-- cyan/blue and cyan/cyan3 -->
        <linearGradient id="grad1b" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:cyan;stop-opacity:1"/>
          <stop offset="100%" style="stop-color:blue;stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2b" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:cyan;stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb( 0, 205, 205);stop-opacity:1"/>
        </linearGradient>
        <!-- turquois -->
        <linearGradient id="grad1t" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb(72,255,242);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb(35,123,118);stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2t" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb(72,255,242);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb(43,154,116);stop-opacity:1"/>
        </linearGradient>
        <!-- gray -->
        <linearGradient id="grad1f" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb(210,210,210);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb(120,120,120);stop-opacity:1"/>
        </linearGradient>
        <linearGradient id="grad2f" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" style="stop-color:rgb(235,235,235);stop-opacity:1"/>
          <stop offset="100%" style="stop-color:rgb(160,160,160);stop-opacity:1"/>
        </linearGradient>
      </defs>
    </svg>