FTUI Widget Bar
Das Bar Widget ist ein Widget für FHEM Tablet UI V2, mit dem ein Reading eines FHEM-Devices in Form eines horizontalen Balkens angezeigt wird.
Es ist nicht in den Standard-Widgets von FTUI2 enthalten, sondern wurde
Attribute
Attribut | Beschreibung | Standard-Wert | Beispiel |
---|---|---|---|
data-device | Name des Device, dessen Reading angezeigt werden soll | data-get="G.Verb" | |
data-get | Name des Readings, dessen Wert angezeigt werden soll | data-get="power" | |
data-part | RegEx oder Nummer des Wortes, nach welcher der angezeigte Text gefiltert werden soll | ||
data-fix | Angegebene Anzahl an Dezimalstellen einhalten | (-1 -> nicht numerisch) | |
data-max | Zahlenwert, bei welchem der Balken zu 100% gefüllt ist | 1 | data-max="20.0" |
data-color | Fester Wert für die Farbe des Balkens. Erlaubte Werte hängen von den Definitionen im SVG-Teil ab, siehe unten. Mit dem unten gegebenem Beispiel sind erlaubte Farben "red", "green", "bue", "pink", "orange" | data-color="pink" | |
data-unit | Einheit nach Zahl hinzufügen | data-unit="m³" | |
data-substitution | Verschiedene Funktionen, um den empfangenen Wert durch etwas anderes zu ersetzen | siehe #Hinweise | |
data-interval | Anzahl Millisekunden, nach denen das Widget aktualisiert werden soll | 0 -> kein Auto-Refresh | data-interval="10" |
CSS Klassen
Klasse | Beschreibung |
---|---|
small | Setzt die Größe des Elementes auf 80% |
large | Setzt die Größe des Elementes auf 125% |
big | Setzt die Größe des Elementes auf 150% |
bigger | Setzt die Größe des Elementes auf 200% |
thin | dünne Schrift |
bold | fette Schrift |
red | Vordergrundfarbe rot |
green | Vordergrundfarbe grün |
blue | Vordergrundfarbe blau |
orange | Vordergrundfarbe orange |
darker | Schriftfarbe grau |
timestamp | Zeigt den Timestamp eines Readings statt dessen Inhalt |
w1x | Einfache fixe Breite |
w2x | Doppelte fixe Breite |
w3x | Dreifache fixe Breite |
circleborder | Runder Rahmen um ein Label-Widget |
squareborder | Eckiger Rahmen um ein Label-Widget |
bg-limit | Ändert bei Label-Widgets die Hinter- statt der Vordergrundfarbe in Abhängigkeit von data-limit |
icon square | Erzeugt einen Hintergrund mit eckigen Kanten |
icon round | Erzeugt einen Hintergrund mit abgerundeten Kanten |
truncate | Text wird - wenn nötig - abgeschnitten und mit "..." ergänzt |
fixedlabel | Verhindert bei verschachtelten labels das Überschreiben von data-get |
blink | Blinkende Animation für Label- oder Switch-Widget |
blurry | Element wird in einen stark verschwommen, grauen Schatten umgewandelt |
shake | Element zittert stark für einen unendlichen Zeitraum. Kann z.B. für eine Alarmglocke verwendet werden. |
Installation
Widget-Datei widget_bar.js
Dazu muss im ersten Schritt eine Widget-Datei widget_bar.js erstellt werden, die (mit den korrekten Rechten) im Verzeichnis /opt/fhem/www/tablet/js gespeichert wird.
/* FTUI Plugin * Copyright (c) 2018 Prof. Dr. Peter A. Henning * GPL License */ /* global ftui:true, Modul_widget:true */ "use strict"; function depends_bar() { var deps =[]; return deps; } var Modul_bar = function () { function drawBar(elem) { var id = elem.prop('id'); var max = elem.data('max'); var val = elem.data('value'); var uni = elem.data('unit'); 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"; } var bar = document.getElementById(id); if (bar) { bar.getElementsByClassName("side")[0].setAttribute("width", val1 + 16); bar.getElementsByClassName("top")[0].setAttribute("x", val1); bar.getElementsByClassName("topline")[0].setAttribute("x", val1); bar.getElementsByClassName("labele")[0].textContent = val + " " + uni; bar.getElementsByClassName("labele")[0].setAttribute("x", textpos); bar.getElementsByClassName("labele")[0].setAttribute("style", style); } } function init_attr(elem) { //init standard attributes base.init_attr.call(me, elem); elem.initData('get', 'STATE'); elem.initData('unit', ''); elem.initData('value', 20); elem.initData('max', 100); elem.initData('font-size', 12); elem.initData('interval', 5000); } function init_ui(elem) { var svg = document.getElementById('svg200x150') var p = document.getElementById("barwidget"); var svg_prime = svg.cloneNode(true); var p_prime = p.cloneNode(true); var bar = svg_prime.appendChild(p_prime); var id = elem.prop('id'); document.getElementById(id).appendChild(svg_prime); var color = elem.data('color'); switch (color) { case "red": bar.getElementsByClassName("side")[0].setAttribute("fill", "url(#grad1r)"); bar.getElementsByClassName("top")[0].setAttribute("fill", "url(#grad2r)"); break; case "green": bar.getElementsByClassName("side")[0].setAttribute("fill", "url(#grad1g)"); bar.getElementsByClassName("top")[0].setAttribute("fill", "url(#grad2g)"); break; case "blue": bar.getElementsByClassName("side")[0].setAttribute("fill", "url(#grad1b)"); bar.getElementsByClassName("top")[0].setAttribute("fill", "url(#grad2b)"); break; case "pink": bar.getElementsByClassName("side")[0].setAttribute("fill", "url(#grad1p)"); bar.getElementsByClassName("top")[0].setAttribute("fill", "url(#grad2p)"); break; case "orange": bar.getElementsByClassName("side")[0].setAttribute("fill", "url(#grad1o)"); bar.getElementsByClassName("top")[0].setAttribute("fill", "url(#grad2o)"); break; } } function update(dev, par) { me.elements.filterDeviceReading('get', dev, par).each(function (index) { var elem = $(this); var val = elem.getReading('get').val; val = ftui.getPart(val, elem.data('part')); val = me.substitution(val, elem.data('substitution')); val = me.map(elem.data('map-get'), val, val); val = me.fix(val, elem.data('fix')); elem.data('value', val); drawBar(elem); }); } // public // inherit all public members from base class var parent = new Modul_widget(); var base = { init_attr: parent.init_attr }; var me = $.extend(parent, { //override or own public members widgetname: 'bar', init_attr: init_attr, init_ui: init_ui, update: update }); return me; };
Auf der FTUI-Seite
Die Seite, auf welcher das Bar-Widget angezeigt werden soll, benötigt einerseit eine unsichtbare SVG-Region, deren sichtbare Kopien später das Widget enthalten werden. Dazu muss irgendwo auf dieser Seite eine HTML-Division eingebaut werden, gerne direkt nach dem <body>-Tag.
<div style="visibility:hidden"> <svg id="svg200x150" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 225" width="200px" height="150px"> </svg> </div>
Außerdem wollen wir natürlich die Farben des Widgets durch schicke Gradienten darstellen, und benötigen die grafische Struktur des Widgets. Dazu gibt es eine SVG-Region, die wegen einer Breite und Höhe von jeweil sNull Pixel unsichtbar ist. Also gleich im Anschluss an die unsichtbare HTML-Division von oben:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 10 10" 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> <!-- ++++++++++++++++++++++++++++++++++++ Bar Widget ++++++++++++++++++++++++++++++++++++++ --> <g id="barwidget"> <g transform="translate(0,65)"> <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 class="side" x="24" y="5" width="40" height="80" rx="20" ry="40" fill="gray"/> <rect class="top" x="24" y="5" width="40" height="80" rx="20" ry="40" fill="gray"/> <rect x="252" y="5" width="40" height="80" rx="20" ry="40" fill="none" stroke="rgb(139, 137, 137)" stroke-width="2"/> <rect class="topline" 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 class="labele" x="28" y="52" fill="rgb(75, 75, 75)" style="font-family:Helvetica;font-size:24px;font-weight:bold;"/> </g> </g> <!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> </defs> </svg>