DOIF/uiTable Anwendung: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| (27 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
An dieser Stelle werden konkrete Anwendungen aufgezeigt, die mit Hilfe des uiTable-Attributes des DOIF-Moduls realisiert wurden. Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition [https://wiki.fhem.de/wiki/Import_von_Code_Snippets] ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. | |||
Die Dokumentation zum Aufbau und Funktionsweise des uiTable-Attributes mit zahlreichen Beispielen ist an dieser Stelle beschrieben: [[DOIF/uiTable_Schnelleinstieg]]. | |||
=== '' Visualisierung und Steuerung von '''Rollläden''''' === | === '' Visualisierung und Steuerung von '''Rollläden''''' === | ||
{{Randnotiz|RNText='''nützliche Links''' | {{Randnotiz|RNText='''nützliche Links''' | ||
| Zeile 8: | Zeile 12: | ||
Im folgenden Beispiel werden Rollläden morgens hochgefahren, ebenso wird die Position aller Rollläden visualisiert. Durch Anklicken eines Icons wird der Rollladen auf die entsprechende Position bewegt. | Im folgenden Beispiel werden Rollläden morgens hochgefahren, ebenso wird die Position aller Rollläden visualisiert. Durch Anklicken eines Icons wird der Rollladen auf die entsprechende Position bewegt. | ||
''Ergebnis des Anwendungsbeispiels in der Webansicht:'' | |||
[[Datei:UiTable Rollladen.png|mini|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 49: | Zeile 49: | ||
TPL_shutter(R_Keller)\ | TPL_shutter(R_Keller)\ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== ''Anzahl der Tage bis zur '''Abfall-Entsorgung''''' === | === ''Anzahl der Tage bis zur '''Abfall-Entsorgung''''' === | ||
| Zeile 58: | Zeile 56: | ||
}} | }} | ||
Mit Hilfe des Kalender-Moduls werden die verbleibenden Tage bis zur Abfall-Entsorgung der jeweiligen Tonne berechnet und mit Hilfe von uiTable visualisiert. Wenn der Tag der Entsorgung bevorsteht, wird er farbig gekennzeichnet. Vorausgesetzt wird die Definition des Kalenders namens 'cal' mit Hilfe des Moduls [[Calendar]]. Dieser muss die Termine der Abfallentsorgung der Tonnen beinhalten. Im Beispiel wird nach Stichwörtern: "Altpapier", "Restmüll", "Bio", "Gelbe" und "Grünabfuhr" im Kalender gesucht. | Mit Hilfe des Kalender-Moduls werden die verbleibenden Tage bis zur Abfall-Entsorgung der jeweiligen Tonne berechnet und mit Hilfe von uiTable visualisiert. Wenn der Tag der Entsorgung bevorsteht, wird er farbig gekennzeichnet. Vorausgesetzt wird die Definition des Kalenders namens 'cal' mit Hilfe des Moduls [[Calendar]]. Dieser muss die Termine der Abfallentsorgung der Tonnen beinhalten. Im Beispiel wird nach Stichwörtern: "Altpapier", "Restmüll", "Bio", "Gelbe" und "Grünabfuhr" im Kalender gesucht. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:Anwendungsbeispiel Abfall.png|mini|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
defmod Abfall DOIF subs {\ | defmod Abfall DOIF subs {\ | ||
| Zeile 113: | Zeile 115: | ||
FOR (@{$_sc},TPL_Tonne($_$2,$_$3)|) | FOR (@{$_sc},TPL_Tonne($_$2,$_$3)|) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== ''Visualisierung: '''offene Fenster''''' === | === ''Visualisierung: '''offene Fenster''''' === | ||
| Zeile 124: | Zeile 123: | ||
}} | }} | ||
Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert. | Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:UiTable windows closed.png|mini|ohne]] | |||
[[Datei:UiTable windows open.png|mini|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
defmod di_uiTable_windows DOIF ## Visualisierung offener Fenster, Fenster-Devices enden mit "Fenster" im Namen | defmod di_uiTable_windows DOIF ## Visualisierung offener Fenster, Fenster-Devices enden mit "Fenster" im Namen | ||
| Zeile 130: | Zeile 134: | ||
icon([$SELF:windows],"fts_window_1w_open\@DarkOrange","fts_window_1w",".*","keine")|[$SELF:windows] | icon([$SELF:windows],"fts_window_1w_open\@DarkOrange","fts_window_1w",".*","keine")|[$SELF:windows] | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== ''Visualisierung: '''aktuelle Wetterlage''''' === | === ''Visualisierung: '''aktuelle Wetterlage''''' === | ||
| Zeile 144: | Zeile 144: | ||
Regenrader animiert, aktuelle Temperatur und Feuchte vom Sensor, aktuelle Wetterlage sowie Wettervorhersage der nächsten Tage. Über entsprechende Weblinks werden Bilder aus dem WWW in der Tabelle visualisiert. Im Gegensatz zu lokalen Sensoren, muss für die Aktualisierung der WWW-Elemente in der jeweiligen Webinstanz (FHEMWEB) das refresh-Attribut gesetzt werden. | Regenrader animiert, aktuelle Temperatur und Feuchte vom Sensor, aktuelle Wetterlage sowie Wettervorhersage der nächsten Tage. Über entsprechende Weblinks werden Bilder aus dem WWW in der Tabelle visualisiert. Im Gegensatz zu lokalen Sensoren, muss für die Aktualisierung der WWW-Elemente in der jeweiligen Webinstanz (FHEMWEB) das refresh-Attribut gesetzt werden. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:UiTable wetter.png|600px|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 170: | Zeile 169: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br clear="all"> | <br clear="all"> | ||
| Zeile 182: | Zeile 179: | ||
Die vorgestellte Lösung funktioniert ohne Anmeldung beim Wetterdienst und ohne Nutzung von API. | Die vorgestellte Lösung funktioniert ohne Anmeldung beim Wetterdienst und ohne Nutzung von API. | ||
Über den Wetterdienst: https://www.wunderground.com/ werden sehr viele private Wifi-Wetterstationen eingebunden. Das kann man sich zunutze machen, indem man zunächst in seiner Umgebung nach Wetterstationen des Dienstes sucht - oft findet man im Umkreis von wenigen Kilometern schon einige Stationen, die rege Wetterdaten liefern. Danach definiert man über HTTPMOD seine Station und visualisiert diese anschließend. | Über den Wetterdienst: https://www.wunderground.com/ werden sehr viele private Wifi-Wetterstationen eingebunden. Das kann man sich zunutze machen, indem man zunächst in seiner Umgebung nach Wetterstationen des Dienstes sucht - oft findet man im Umkreis von wenigen Kilometern schon einige Stationen, die rege Wetterdaten liefern. Danach definiert man über HTTPMOD seine Station und visualisiert diese anschließend. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:UiTable ringwetter.png|600px|ohne]] | |||
Definition einer Station in der Nachbarschaft. <StationsID> muss gegen die korrekte Stationsnummer ersetzt werden. | Definition einer Station in der Nachbarschaft. <StationsID> muss gegen die korrekte Stationsnummer ersetzt werden. | ||
| Zeile 239: | Zeile 239: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br clear="all"> | <br clear="all"> | ||
Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion '''card''': | Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion '''card''': | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:UiTable svgwetter.png|800px|ohne]] | |||
Ohne Angabe der Überschrift (undef für $header setzen) lässt sich eine kompaktere Darstellung erzielen: | |||
[[Datei:UiTable svgwetteroh.png|800px|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 263: | Zeile 268: | ||
card([Wetter:LuftdruckHpa:col3d],"Luftdruck","weather_barometric_pressure",980,1047,30,90,"hPa",undef,0) | card([Wetter:LuftdruckHpa:col3d],"Luftdruck","weather_barometric_pressure",980,1047,30,90,"hPa",undef,0) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br clear="all"> | <br clear="all"> | ||
| Zeile 285: | Zeile 282: | ||
Zunächst wird ein HTTPMOD-Modul für den aktuellen Spritpreis definiert, dabei ist <Stations-ID> durch die ID der Tankstelle zu ersetzen. | Zunächst wird ein HTTPMOD-Modul für den aktuellen Spritpreis definiert, dabei ist <Stations-ID> durch die ID der Tankstelle zu ersetzen. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:Di uiTable Tankstelle.png|ohne|mini]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 303: | Zeile 298: | ||
attr Tankstelle timeout 10 | attr Tankstelle timeout 10 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Visualisierung der Preisentwicklung der letzten 24 Stunden: | |||
''Ergebnis der Beispieldefinition in der Webansicht:'' | ''Ergebnis der Beispieldefinition in der Webansicht:'' | ||
[[Datei:Di uiTable sprit.png|ohne|mini]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 314: | Zeile 310: | ||
card([[Tankstelle:SuperE5:col3d],[Tankstelle:Diesel:col3d]],undef,"fuel\@silver",1.40,1.9,120,0,["E10","Diesel"],undef,"2,,fill:silver, €","130,autoscaling,steps,footer,ycolor,ring,200",undef,undef) | card([[Tankstelle:SuperE5:col3d],[Tankstelle:Diesel:col3d]],undef,"fuel\@silver",1.40,1.9,120,0,["E10","Diesel"],undef,"2,,fill:silver, €","130,autoscaling,steps,footer,ycolor,ring,200",undef,undef) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== ''Visualisierung: '''aktuelle Corona-7-Tage-Inzidenz''''' === | === ''Visualisierung: '''aktuelle Corona-7-Tage-Inzidenz''''' === | ||
| Zeile 328: | Zeile 321: | ||
Zunächst wird ein JsonMod Device für das Auslesen der Inzidenzzahlen definiert. Die gewünschten Regionen müssen für eigene Bedürfnisse angepasst werden. | Zunächst wird ein JsonMod Device für das Auslesen der Inzidenzzahlen definiert. Die gewünschten Regionen müssen für eigene Bedürfnisse angepasst werden. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:uiTable_Inzidenz.png|600px|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 345: | Zeile 338: | ||
card([RKI7:Stadteregion_Aachen:col1w],"Aachen","coronavirus",0,200,120,0,"Fälle") | card([RKI7:Stadteregion_Aachen:col1w],"Aachen","coronavirus",0,200,120,0,"Fälle") | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br clear="all"> | <br clear="all"> | ||
| Zeile 362: | Zeile 352: | ||
}} | }} | ||
Definition eines DOIF-Devices zur Steuerung der Therme und Visualisierung der Daten. Es werden Readings und Befehle genutzt, die durch den MQTT2-Server zur Verfügung gestellt werden. Einzelne Heizungswerte werden in bestimmten Intervallen über den publish-Befehl ausgelesen. Die Temperaturen der Zirkulation, des Vorlaufs und des Rücklaufs werden außerhalb der Therme mit 1-wire-Temperatursensoren über WLAN-ESP-Easy ausgelesen. Die Definition des Layouts über das Attribut uiTable ist unabhängig vom Auslesen der Werte, sie bezieht sich lediglich auf vorhandene Readings, die visualisiert werden sollen. Das Layout kann ebenso auf Readings aus anderen Devices der eigenen FHEM-Umgebung anpasst werden. | Definition eines DOIF-Devices zur Steuerung der Therme und Visualisierung der Daten. Es werden Readings und Befehle genutzt, die durch den MQTT2-Server zur Verfügung gestellt werden. Einzelne Heizungswerte werden in bestimmten Intervallen über den publish-Befehl ausgelesen. Die Temperaturen der Zirkulation, des Vorlaufs und des Rücklaufs werden außerhalb der Therme mit 1-wire-Temperatursensoren über WLAN-ESP-Easy ausgelesen. Die Definition des Layouts über das Attribut uiTable ist unabhängig vom Auslesen der Werte, sie bezieht sich lediglich auf vorhandene Readings, die visualisiert werden sollen. Das Layout kann ebenso auf Readings aus anderen Devices der eigenen FHEM-Umgebung anpasst werden. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:Di uiTable Heizung.png|800px|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 426: | Zeile 419: | ||
card([$SELF:diff_hwc:col],"Energie Warmwasser","sani_water_tap",0,15,120,0,"kWh",undef,1) | card([$SELF:diff_hwc:col],"Energie Warmwasser","sani_water_tap",0,15,120,0,"kWh",undef,1) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br clear="all"> | <br clear="all"> | ||
| Zeile 440: | Zeile 430: | ||
Die aktuelle Anwesenheit von Heimbewohnern wird visualisiert.<br><br> | Die aktuelle Anwesenheit von Heimbewohnern wird visualisiert.<br><br> | ||
Zunächst wird mit Hilfe des Moduls [[FRITZBOX]] ein Device namens ''FritzBox'' erstellt. Dort werden die eingebuchten Smartphones der Bewohner mit Ihren MAC-Adressen in Readings abgelegt. Die folgende Definition wertet aus, ob die angegebenen MAC-Adressen als Readings vorhanden sind und erstellt für jeden Bewohner ein Reading mit den Zuständen on/off. Diese Readings werden dann über das Attribut uiTable visualisiert. Die anwesenden Personen werden farblich markiert. Die Namen der Personen sowie die MAC-Adressen sind fiktiv und müssen den eigenen Angaben entsprechend angepasst werden. | Zunächst wird mit Hilfe des Moduls [[FRITZBOX]] ein Device namens ''FritzBox'' erstellt. Dort werden die eingebuchten Smartphones der Bewohner mit Ihren MAC-Adressen in Readings abgelegt. Die folgende Definition wertet aus, ob die angegebenen MAC-Adressen als Readings vorhanden sind und erstellt für jeden Bewohner ein Reading mit den Zuständen on/off. Diese Readings werden dann über das Attribut uiTable visualisiert. Die anwesenden Personen werden farblich markiert. Die Namen der Personen sowie die MAC-Adressen sind fiktiv und müssen den eigenen Angaben entsprechend angepasst werden. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:UiTable myHome.png|ohne|mini]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 473: | Zeile 466: | ||
}} | }} | ||
Die vorgestellte Lösung visualisiert in kompakter Form den aktuellen Stromfluss des Hauses. Der Energiefluss wird abhängig von der Leistung und der Flussrichtung animiert. Die Definition muss an eigene Bedürfnisse angepasst werden. Dazu müssen die Variablen für die maximale Leistung am Anfang der Definition angepasst sowie im Attribut DOIF_Readings die eigenen Readings angegeben werden. Die Größe der Grafik ist über das CSS-Attribut zoom beliebig skalierbar (siehe im Device-Attribut uiTable Variable $TABLE). Im Definitionsbereich des DOIF-Devices sind alle erforderlichen Perlfunktionen definiert. Es wird vornehmlich die SVG-Funktion icon_ring2 des DOIF-Moduls benutzt. Im Attribut uiTable sind die einzelnen Visualisierungselemente als zuvor definierte Perlfunktionen angegeben. Falls der Batterie-Speicher nicht visualisiert werden soll, so können die beiden Zeilen beginnend mit "battery" gelöscht werden. Die programmierten Perlfunktionen können an eigene Bedürfnisse angepasst werden. So könnten z. B. ein E-Auto oder eine Wärmepumpe dargestellt werden. Es werden keine weiteren Perlfunktionen oder Javascripte außerhalb des DOIF-Devices benötigt. Vorausgesetzt wird die DOIF-Version: # $Id: 98_DOIF.pm 31131 2026-04-17 18:27:58Z Damian $ oder neuer. | Die vorgestellte Lösung visualisiert in kompakter Form den aktuellen Stromfluss des Hauses. Der Energiefluss wird abhängig von der Leistung und der Flussrichtung animiert. Die Definition muss an eigene Bedürfnisse angepasst werden. Dazu müssen die Variablen für die maximale Leistung am Anfang der Definition angepasst sowie im Attribut DOIF_Readings die eigenen Readings angegeben werden. Die Größe der Grafik ist über das CSS-Attribut zoom beliebig skalierbar (siehe im Device-Attribut uiTable Variable $TABLE). Im Definitionsbereich des DOIF-Devices sind alle erforderlichen Perlfunktionen definiert. Es wird vornehmlich die SVG-Funktion icon_ring2 des DOIF-Moduls benutzt. Im Attribut uiTable sind die einzelnen Visualisierungselemente als zuvor definierte Perlfunktionen angegeben. Falls der Batterie-Speicher nicht visualisiert werden soll, so können die beiden Zeilen beginnend mit "battery" gelöscht werden. Die programmierten Perlfunktionen können an eigene Bedürfnisse angepasst werden. So könnten z. B. ein E-Auto oder eine Wärmepumpe dargestellt werden. Es werden keine weiteren Perlfunktionen oder Javascripte außerhalb des DOIF-Devices benötigt. Vorausgesetzt wird die DOIF-Version: # $Id: 98_DOIF.pm 31131 2026-04-17 18:27:58Z Damian $ oder neuer. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:uiTable_energy_card_compact.gif|mini|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 647: | Zeile 643: | ||
self([$SELF:autarchy],[$SELF:scr]) | self([$SELF:autarchy],[$SELF:scr]) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== ''Visualisierung: '''Energiefluss als Energie-Karte''''' === | === ''Visualisierung: '''Energiefluss als Energie-Karte''''' === | ||
| Zeile 655: | Zeile 648: | ||
* svg-Funktion [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card card] | * svg-Funktion [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card card] | ||
}} | }} | ||
Hier wird eine Version der Energie-Karte mit Hilfe der | Hier wird eine Version der Energie-Karte mit Hilfe der SVG-Funktion card des DOIF-Moduls realisiert. In dieser Darstellung wird zusätzlich der Verlauf der jeweiligen Leistungen und der Speicherkapazität visualisiert. Die Konfiguration bzw. Anpassung an eigene Bedürfnisse sind wie bei der kompakten Energie-Karte oben vorzunehmen. Sollten beide Version gleichzeitig genutzt werden wollen, dann müssen die programmierten Perlfunktionen einer Version umbenannt werden, sonst überschreiben sie sich gegenseitig, weil sie im gleichen Package liegen. | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:uiTable_energy_card.gif|ohne]] | |||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
| Zeile 827: | Zeile 823: | ||
self([$SELF:autarchy],[$SELF:scr]) | self([$SELF:autarchy],[$SELF:scr]) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Weiterführende Links === | === Weiterführende Links === | ||
Aktuelle Version vom 26. April 2026, 10:57 Uhr
An dieser Stelle werden konkrete Anwendungen aufgezeigt, die mit Hilfe des uiTable-Attributes des DOIF-Moduls realisiert wurden. Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition [1] ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden.
Die Dokumentation zum Aufbau und Funktionsweise des uiTable-Attributes mit zahlreichen Beispielen ist an dieser Stelle beschrieben: DOIF/uiTable_Schnelleinstieg.
Visualisierung und Steuerung von Rollläden
- Zeitsteuerung
- uiTable-Funktion shutter
- uiTable-Funktion style
- Templates
Im folgenden Beispiel werden Rollläden morgens hochgefahren, ebenso wird die Position aller Rollläden visualisiert. Durch Anklicken eines Icons wird der Rollladen auf die entsprechende Position bewegt.
Ergebnis des Anwendungsbeispiels in der Webansicht:

defmod DI_Rollladen DOIF (([Dunkelheit] eq "off" and [06:25-09:00|8]) or [09:00|7]) \
((set R_W_S,R_W_W[1-3] on)) ## Hochfahren der Rollläden im Erdgeschoss morgens\
DOELSEIF ([Dunkelheit] eq "on")
attr DI_Rollladen cmdState oben|unten
attr DI_Rollladen devStateIcon unten:status_night oben:scene_day
attr DI_Rollladen icon fts_shutter_automatic
attr DI_Rollladen uiTable {\
package ui_Table;;\
}\
\
## Template für ein Fenster\
DEF TPL_shutter("$1"|shutter([$1:pct]))\
\
## Tabellendefinition\
\
style("Dachgeschoss","Darkorange")|""\
TPL_shutter(R_Dachboden)\
style("erstes Geschoss","Darkorange")|""\
TPL_shutter(R_Bad)\
TPL_shutter(R_Kinderzimmer1_O)\
TPL_shutter(R_Kinderzimmer1_S)\
TPL_shutter(R_Kinderzimmer2_S)\
TPL_shutter(R_Kinderzimmer2_W1)\
TPL_shutter(R_Kinderzimmer2_W2)\
style("Erdgeschoss","Darkorange")|""\
TPL_shutter(R_Kueche)\
TPL_shutter(R_W_S)\
TPL_shutter(R_W_W1)\
TPL_shutter(R_W_W2)\
TPL_shutter(R_W_W3)\
style("Keller","Darkorange")|""\
TPL_shutter(R_Keller)\
Anzahl der Tage bis zur Abfall-Entsorgung
- FHEM-Modul Calendar
- ui_Table Funktion icon_label
Mit Hilfe des Kalender-Moduls werden die verbleibenden Tage bis zur Abfall-Entsorgung der jeweiligen Tonne berechnet und mit Hilfe von uiTable visualisiert. Wenn der Tag der Entsorgung bevorsteht, wird er farbig gekennzeichnet. Vorausgesetzt wird die Definition des Kalenders namens 'cal' mit Hilfe des Moduls Calendar. Dieser muss die Termine der Abfallentsorgung der Tonnen beinhalten. Im Beispiel wird nach Stichwörtern: "Altpapier", "Restmüll", "Bio", "Gelbe" und "Grünabfuhr" im Kalender gesucht.
Ergebnis der Beispieldefinition in der Webansicht:

defmod Abfall DOIF subs {\
## Hier reicht es den Kalender-Eintrag anzupassen\
## Kalender-Eintrag, Reading, icon \
push @{$_sc},["Altpapier","altpapier","Abfalltonne-Recycling-Logo\@blue"];;\
push @{$_sc},["Restmüll","restmuell","Abfalltonne\@gray"];;\
push @{$_sc},["Bio","bio","Abfalltonne-Recycling-Logo\@green"];;\
push @{$_sc},["Gelbe","gelbe_tonne","Abfalltonne-Recycling-Logo\@yellow"];;\
push @{$_sc},["Grünabfuhr","gruenschnitt","Gartenabfall\@green"];;\
\
sub days \
{\
my ($event,$reading)=@_;;\
my $days=fhem('get cal events timeFormat:"%j" filter:field(summary)=~"'.$event.'" limit:count=1,from=0 format:custom="$T1"',1);;\
my $date=fhem('get cal events timeFormat:"%a. %d.%m." filter:field(summary)=~"'.$event.'" limit:count=1,from=0 format:custom="$T1"',1);;\
my $diff;;\
if (defined($days) and $days ne "") {\
my $now=::strftime ('%j', localtime());;\
my $year=::strftime ('%Y', localtime());;\
$diff=$days-$now;;\
if ($diff < 0) {\
$diff+=(365+($year % 4 eq 0 and $year % 100 ne 0 or $year % 400 eq 0 ? 1: 0));;\
}\
} else {\
$date="";;\
$diff="N/A"\
}\
set_Reading($reading."_date",$date);;\
set_Reading($reading,$diff,1);;\
}\
sub update\
{\
for (my $i=0;;$i < @{$_sc};;$i++) {\
days($_sc[$i][0],$_sc[$i][1]);;\
}\
}\
}\
init{[00:00];;set_Exec("Timer",60,'update()');;}\
update{update()}
attr Abfall room wiki->abfall
attr Abfall uiTable {\
package ui_Table;;\
$TABLE="text-align:center";;\
$SHOWNOSTATE=1;;\
sub ic\
{\
my ($icon,$days)=@_;;\
icon_label($icon,$days,"white",$days eq "N/A" ? "blue" : $days > 1 ? "#606060" : "red")\
}\
}\
\
DEF TPL_Tonne (style([$SELF:$1_date],"",8),ic ('$2',[$SELF:$1]))\
\
FOR (@{$_sc},TPL_Tonne($_$2,$_$3)|)
Visualisierung: offene Fenster
- Attribut DOIF_Readings
- DOIF-Aggregationsfunktionen
- uiTable-Funktion icon
Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert.
Ergebnis der Beispieldefinition in der Webansicht:


defmod di_uiTable_windows DOIF ## Visualisierung offener Fenster, Fenster-Devices enden mit "Fenster" im Namen
attr di_uiTable_windows DOIF_Readings windows:[@as(<br>)"Fenster$":state:"open","keine"]
attr di_uiTable_windows uiTable {package ui_Table;;}\
icon([$SELF:windows],"fts_window_1w_open\@DarkOrange","fts_window_1w",".*","keine")|[$SELF:windows]
Visualisierung: aktuelle Wetterlage
- DWD Homepage
- Regenradar Radarfilm BRD
- aktuelles Wetter NRW
- Wetteronline eignes Widget
Regenrader animiert, aktuelle Temperatur und Feuchte vom Sensor, aktuelle Wetterlage sowie Wettervorhersage der nächsten Tage. Über entsprechende Weblinks werden Bilder aus dem WWW in der Tabelle visualisiert. Im Gegensatz zu lokalen Sensoren, muss für die Aktualisierung der WWW-Elemente in der jeweiligen Webinstanz (FHEMWEB) das refresh-Attribut gesetzt werden.
Ergebnis der Beispieldefinition in der Webansicht:

defmod di_uiTable_wetter DOIF ##
attr di_uiTable_wetter uiTable {\
package ui_Table;;\
$TC{1}="align='center'";;\
}\
## das Attribut 'refresh' der Webinstanz für ein Wandtablet wurde auf 900 gesetzt, damit die Bilder alle 15 Minuten aktualisiert werden \
## Tabellendefinition\
\
## Regenradar BRD\
'<img src="https://www.dwd.de/DWD/wetter/radar/radfilm_brd_akt.gif" height="365px" width="365px">'|\
\
## Aktuelle Temperatur und Feuchtigkeit vom lokalen sensor\
temp([Aussensensor:temperature],40),hum ([Aussensensor:humidity],30),\
\
## aktuelle Wetterlage NRW\
"<img src ='https://www.dwd.de/DE/wetter/wetterundklima_vorort/nordrhein-westfalen/_functions/bildgalerie/wetter_aktuell.jpg?view=nasImage&nn=561200' height='255px' width='255px'>"|\
\
## Wettervorhersage\
"<iframe marginheight='0' marginwidth='0' scrolling='no' width='300' height='365' name='FC3' style='border:1px solid;;border-color:#00537f;;' src='https://api.wetteronline.de/wetterwidget?gid=x0677&modeid=FC3&seourl=juelich&locationname=Jülich&lang=de'></iframe>"\
Visualisierung: Wetterstation
Die vorgestellte Lösung funktioniert ohne Anmeldung beim Wetterdienst und ohne Nutzung von API. Über den Wetterdienst: https://www.wunderground.com/ werden sehr viele private Wifi-Wetterstationen eingebunden. Das kann man sich zunutze machen, indem man zunächst in seiner Umgebung nach Wetterstationen des Dienstes sucht - oft findet man im Umkreis von wenigen Kilometern schon einige Stationen, die rege Wetterdaten liefern. Danach definiert man über HTTPMOD seine Station und visualisiert diese anschließend.
Ergebnis der Beispieldefinition in der Webansicht:

Definition einer Station in der Nachbarschaft. <StationsID> muss gegen die korrekte Stationsnummer ersetzt werden.
defmod Wetter HTTPMOD https://www.wunderground.com/dashboard/pws/<StationsID>
attr Wetter enableControlSet 1
attr Wetter reading01Name Wind
attr Wetter reading01Regex stationID(?!.*stationID).*windspeedAvg":([\d+\.]+)
attr Wetter reading02Name Windboeen
attr Wetter reading02Regex stationID(?!.*stationID).*windgustAvg":([\d+\.]+)
attr Wetter reading03Name Windrichtung
attr Wetter reading03Regex stationID(?!.*stationID).*winddirAvg":([\d+\.]+)
attr Wetter reading04Name Regen
attr Wetter reading04Regex stationID(?!.*stationID).*precipRate":([\d+\.]+)
attr Wetter reading05Name RegenGesamt
attr Wetter reading05Regex stationID(?!.*stationID).*precipTotal":([\d+\.]+)
attr Wetter reading06Name Temperatur
attr Wetter reading06Regex stationID(?!.*stationID).*tempAvg":([\d+\.]+)
attr Wetter reading07Name Feuchtigkeit
attr Wetter reading07Regex stationID(?!.*stationID).*humidityAvg":([\d+\.]+)
attr Wetter reading08Name UV
attr Wetter reading08Regex stationID(?!.*stationID).*uvHigh":([\d+\.]+)
attr Wetter reading09Name Luftdruck
attr Wetter reading09Regex stationID(?!.*stationID).*pressureMin":([\d+\.]+)
attr Wetter reading10Name TemperaturGefuehlt
attr Wetter reading10Regex stationID(?!.*stationID).*windchillAvg":([\d+\.]+)
attr Wetter reading11Name TaupunktTemp
attr Wetter reading11Regex stationID(?!.*stationID).*dewptAvg":([\d+\.]+)
attr Wetter reading12Name Sonnenstrahlung
attr Wetter reading12Regex stationID(?!.*stationID).*solarRadiationHigh":([\d+\.]+)
attr Wetter room Wetter
attr Wetter timeout 10
attr Wetter userReadings WindKm {sprintf("%1.1f",ReadingsVal($name,"Wind",0)*1.60934)},\
WindboeenKm {sprintf("%1.1f",ReadingsVal($name,"Windboeen",0)*1.60934)},\
WindrichtungGrad {ReadingsVal($name,"Windrichtung",0)-180},\
RegenMm {ReadingsVal($name,"Regen",0)*25.4},\
RegenGesamtMm {ReadingsVal($name,"RegenGesamt",0)*25.4},\
TemperaturC {sprintf("%1.1f",(ReadingsVal($name,"Temperatur",0)-32)*5/9)},\
TaupunktTempC {sprintf("%1.1f",(ReadingsVal($name,"TaupunktTemp",0)-32)*5/9)},\
LuftdruckHpa {sprintf("%d",ReadingsVal($name,"Luftdruck",0)*33.8639)},\
TemperaturGefuehltC {sprintf("%1.1f",(ReadingsVal($name,"TemperaturGefuehlt",0)-32)*5/9)}
Nun erfolgt die Visualisierung der Daten.
defmod di_Wetter_ring DOIF ##
attr di_Wetter_ring uiTable {package ui_Table;;}\
\
icon_temp_hum_ring("temp_outside",[Wetter:TemperaturC],[Wetter:Feuchtigkeit],undef,undef,150)|\
icon_temp_ring ("temp_windchill",[Wetter:TemperaturGefuehltC],undef,undef,150) |\
icon_temp_ring ("temperature_humidity",[Wetter:TaupunktTempC],undef,undef,150) |\
icon_ring2([Wetter:WindKm] > 0 ? "wind".",1,0,0,".[Wetter:WindrichtungGrad]:"no_wind",[Wetter:WindKm],0,50,120,0,"km/h",150,undef,1,[Wetter:WindboeenKm],0,50,120,0,"km/h",undef,1) |\
icon_ring2("weather_rain_gauge",[Wetter:RegenMm],0,10,180,270,"mm/h",150,undef,1,[Wetter:RegenGesamtMm],0,50,180,270,"mm",undef,1)|\
icon_ring2("sani_solar",[Wetter:UV],0,10,100,30,"UV",150,undef,0,[Wetter:Sonnenstrahlung],0,1000,100,30,"Watt/m²",undef,0)|\
icon_ring ("weather_barometric_pressure",[Wetter:LuftdruckHpa],980,1047,0,120,"hPa",0,150)
Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion card:
Ergebnis der Beispieldefinition in der Webansicht:

Ohne Angabe der Überschrift (undef für $header setzen) lässt sich eine kompaktere Darstellung erzielen:

defmod di_Wetter DOIF ##
attr di_Wetter icon weather_wind
attr di_Wetter uiTable {package ui_Table;;}\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness)\
\
card([Wetter:TemperaturC:col3d],"Außentemperatur","temp_outside",-10,60,undef,undef,"°C",\&temp_hue)|\
card([Wetter:TemperaturGefuehltC:col3d],"gefühlte Temperatur","temp_windchill",-10,60,undef,undef,"°C",\&temp_hue)|\
card([Wetter:TaupunktTempC:col3d],"Taupunkttemperatur","temperature_humidity",-10,60,undef,undef,"°C",\&temp_hue)|\
card([Wetter:Feuchtigkeit:col3d],"Außenfeuchtigkeit","temperature_humidity",0,100,undef,undef,"%",\&hum_hue)|\
card([Wetter:WindKm:col3d],"Wind",[Wetter:WindKm] > 0 ? "wind".",1,0,0,".[Wetter:WindrichtungGrad]:"no_wind",0,30,90,30,"km/h",undef,1)\
card([Wetter:WindboeenKm:col3d],"Windböen","weather_wind",0,30,90,30,"km/h",undef,1)|\
card([Wetter:RegenMm:col3d],"Regen","weather_rain_gauge",0,10,180,270,"mm/h")|\
card([Wetter:RegenGesamtMm:col3d],"Regengesamt","weather_rain_gauge",0,50,180,270,"mm")|\
##card([Wetter:UV:col3d],"UV-Strahlung","sani_solar",0,7,100,30,"UV",undef,0)|\
card([Wetter:Sonnenstrahlung:col3d],"Sonnenstrahlung","sani_solar",0,1000,30,90,"Watt/m²",undef,0)|\
card([Wetter:LuftdruckHpa:col3d],"Luftdruck","weather_barometric_pressure",980,1047,30,90,"hPa",undef,0)
Visualisierung: aktueller Spritpreis
- svg-Funktion ring
- svg-Funktion card
- Tankstelle bestimmen Clever tanken
- Modul HTTPMOD
Der aktuelle Spritpreis einer Tankstelle wird ermittelt und mit seinem zeitlichen Verlauf visualisiert.
Zunächst wird ein HTTPMOD-Modul für den aktuellen Spritpreis definiert, dabei ist <Stations-ID> durch die ID der Tankstelle zu ersetzen.
Ergebnis der Beispieldefinition in der Webansicht:

defmod Tankstelle HTTPMOD http://www.clever-tanken.de/tankstelle_details/<Stations-ID> 300
attr Tankstelle devStateIcon {ui_Table::ring(ReadingsVal("$name","Diesel",0),1.00,1.40,120,0,"Diesel",90,undef,2)." ".ui_Table::ring(ReadingsVal("$name","SuperE5",0),1.10,1.60,120,0,"E5",90,undef,2)}
attr Tankstelle enableControlSet 1
attr Tankstelle event-on-change-reading .*
attr Tankstelle group Spritpreise
attr Tankstelle reading01Name Diesel
attr Tankstelle reading01Regex "current-price-1">(\d.\d{2})
attr Tankstelle reading02Name SuperE5
attr Tankstelle reading02Regex "current-price-2">(\d.\d{2})
attr Tankstelle room Spritpreise
attr Tankstelle timeout 10
Visualisierung der Preisentwicklung der letzten 24 Stunden:
Ergebnis der Beispieldefinition in der Webansicht:

defmod sprit DOIF ##
attr sprit uiTable {package ui_Table;;}\
card([[Tankstelle:SuperE5:col3d],[Tankstelle:Diesel:col3d]],undef,"fuel\@silver",1.40,1.9,120,0,["E10","Diesel"],undef,"2,,fill:silver, €","130,autoscaling,steps,footer,ycolor,ring,200",undef,undef)
Visualisierung: aktuelle Corona-7-Tage-Inzidenz
Die aktuellen Inzidenzwerte werden vom RKI ausgelesen und deren Verlauf visualisiert.
Zunächst wird ein JsonMod Device für das Auslesen der Inzidenzzahlen definiert. Die gewünschten Regionen müssen für eigene Bedürfnisse angepasst werden.
Ergebnis der Beispieldefinition in der Webansicht:

defmod RKI7 JsonMod https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=last_update,cases7_per_100k,BEZ,BEM,GEN,BL,county&returnGeometry=false&outSR=4326&f=json
attr RKI7 readingList multi(jsonPath("\$.features[?(\@.attributes.GEN in ['Städteregion Aachen', 'Düren', 'Heinsberg'])]"), property('attributes.GEN'), sprintf('%.1f', property('attributes.cases7_per_100k')));;
Visualisierung der Inzidenzzahlen der letzten sieben Tage:
defmod di_corona DOIF ##
attr di_corona uiTable {package ui_Table}\
card([RKI7:Duren:col1w],"Düren","coronavirus",0,200,120,0,"Fälle")|\
card([RKI7:Heinsberg:col1w],"Heinsberg","coronavirus",0,200,120,0,"Fälle")|\
card([RKI7:Stadteregion_Aachen:col1w],"Aachen","coronavirus",0,200,120,0,"Fälle")
Visualisierung und Steuerung: Heiztherme
Im folgenden Beispiel wurde eine Heiztherme über einen ebus-Adapter in FHEM eingebunden. Die Heizungsdaten werden über MQTT ausgelesen und anschließend visualisiert. Die vorgestellten Visualisierungsbeispiele können ebenso im funktionslosen DOIF mit Hilfe des uiTable-Attriutes auf bereits existierende Readings des eigenen Systems angewendet werden.
- svg-Funktion icon_ring
- svg-Funktion card
- Commandref DOIF Perl-Modus
- ebus-Adapter ebusd
- ebus-Wiki ebus
Definition eines DOIF-Devices zur Steuerung der Therme und Visualisierung der Daten. Es werden Readings und Befehle genutzt, die durch den MQTT2-Server zur Verfügung gestellt werden. Einzelne Heizungswerte werden in bestimmten Intervallen über den publish-Befehl ausgelesen. Die Temperaturen der Zirkulation, des Vorlaufs und des Rücklaufs werden außerhalb der Therme mit 1-wire-Temperatursensoren über WLAN-ESP-Easy ausgelesen. Die Definition des Layouts über das Attribut uiTable ist unabhängig vom Auslesen der Werte, sie bezieht sich lediglich auf vorhandene Readings, die visualisiert werden sollen. Das Layout kann ebenso auf Readings aus anderen Devices der eigenen FHEM-Umgebung anpasst werden.
Ergebnis der Beispieldefinition in der Webansicht:

defmod di_vaillant DOIF ##{[+00:01];;foreach (qw(FanSpeed Flame PumpPower Storageloadpump PrimaryCircuitFlowrate FlowTempDesired PumpHours HcHours HcPumpStarts)) {fhem_set("MQTT2_FHEM_Server publish ebusd/bai/$_/get")}}\
\
{[+[1]:01];;foreach (qw(PrEnergySumHc1 PrEnergySumHwc1 HcHours HwcHours z1OpMode WaterPressure z1NightTemp z1DayTemp Hc1HeatCurve HwcLockTime HolidayStartPeriod HolidayEndPeriod)) {fhem_set("MQTT2_FHEM_Server publish ebusd/bai/$_/get")}\
}\
\
{[+00:00:30];;foreach (qw(Flame PrimaryCircuitFlowrate)) {fhem_set("MQTT2_FHEM_Server publish ebusd/bai/$_/get")}}\
\
{[00:01];;foreach (qw(FanHours HcStarts HwcStarts )) {fhem_set("MQTT2_FHEM_Server publish ebusd/bai/$_/get")}\
set_Reading("gesamt_hc",int([?vaillant:PrEnergySumHc1_0_value]/10000)/10,0);;\
set_Reading("gesamt_hwc",int([?vaillant:PrEnergySumHwc1_0_value]/10000)/10,0);;\
set_Reading("diff_hc",0,1);;\
set_Reading("diff_hwc",0,1);;\
set_Reading("diff_h",0,1)\
}\
\
{if ([00:05|WE]) {fhem_set("MQTT2_FHEM_Server publish ebusd/700/BankHolidayStartPeriod/set $mday.$month.$year");;fhem_set("MQTT2_FHEM_Server publish ebusd/700/BankHolidayEndPeriod/set $mday.$month.$year")}}\
\
Timer {\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Monday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Tuesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Wednesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Thursday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Friday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Sunday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-"\
fhem_set "MQTT2_FHEM_Server publish ebusd/700/z1Timer.Saturday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-"\
}\
\
diff {\
set_Reading("diff_hc",int(([vaillant:PrEnergySumHc1_0_value]/100000-get_Reading("gesamt_hc",0))*10)/10,1);;\
set_Reading("diff_hwc",int(([vaillant:PrEnergySumHwc1_0_value]/100000-get_Reading("gesamt_hwc",0))*10)/10,1);;\
set_Reading("diff_h",get_Reading("diff_hc")+get_Reading("diff_hwc"),1);;\
}\
\
attr di_vaillant event-on-change-reading .*
attr di_vaillant room Ebus
attr di_vaillant uiTable {\
package ui_Table;;\
$TABLE='text-align:center;;';;\
$SHOWNODEVICELINE = "test9|Damian";;\
}\
icon_temp_ring("temp_outside",[vaillant:Aussentemp],-15,40,130)|\
icon_temp_mring(([vaillant:Flame] eq "off"?"sani_boiler_temp\@white":"sani_boiler_temp\@Darkorange"),[vaillant:Vorlauf],15,70,130)|\
icon_temp_mring(([vaillant:Pumpenstatus] eq "4" ? "sani_buffer_temp_down\@Darkorange" : "sani_buffer_temp_down\@white"),[vaillant:WWSpeicher],15,70,130)|\
icon_uring("0,0,1","weather_barometric_pressure",[vaillant:Wasserdruck],0,3,undef,undef,"bar",1,130,[(0.8,0,1,60,1.5,120,1.7,60,3,0)],"50,35")|\
icon_ring("sani_floor_heating_neutral",[vaillant:HcHours_hoursum2_value],0,10000,120,0,"h",0,130)|\
icon_ring("sani_water_tap",[vaillant:HwcHours_hoursum2_value],0,2000,120,0,"h",0,130)|\
\
icon_ring("time_graph",[vaillant:HeizKennlinie],0.4,1,120,0,"HK",1,130)|\
icon_temp_mring("scene_day\@yellow",[vaillant:TagSolltemp],undef,undef,130)|\
icon_temp_mring("scene_night\@#3464eb",[vaillant:NachtSolltemp],undef,undef,130)\
""|""|""|""|""|""|widget([vaillant:HeizKennlinie],"selectnumbers,0.4,.1,1,1,lin","set")|widget([vaillant:TagSolltemp],"selectnumbers,15,1,25,1,lin","set")|widget([vaillant:NachtSolltemp],"selectnumbers,15,1,25,1,lin","set")<\
\
card([vaillant:Aussentemp:col],"Außentemperatur","temp_outside",-15,35,undef,undef,"°C",\&temp_hue)|\
card([vaillant:WWSpeicher:col],"WW-Speicher",([vaillant:Pumpenstatus] eq "4" ? "sani_buffer_temp_down\@Darkorange" : "sani_buffer_temp_down\@white"),15,70,undef,undef,"°C",\&temp_hue)|\
card([ESPEasy_ESP_Temp_Vorlauf:Temperature:col],"Vorlauf",([vaillant:Pumpenstatus] eq "on" ? "sani_floor_heating\@Darkorange" : "sani_floor_heating_neutral\@white"),15,70,undef,undef,"°C",\&temp_hue)|\
card([$SELF:diff_hc:col],"Energie Heizung","sani_floor_heating_neutral",0,100,120,0,"kWh",undef,1)\
card([vaillant:Umlaufmenge:col],"Umlaufmenge","sani_pump",0,20,120,0,"l/min")|\
card([ESPEasy_ESP_Temp_Zirkulation:Temperature:col],"Zirkulation",([Zirk] eq "off"?"sani_pump\@white":"sani_pump\@Darkorange"),15,70,undef,undef,"°C",\&temp_hue)|\
card([ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature:col],"Rücklauf","sani_floor_heating_neutral\@wite",15,70,undef,undef,"°C",\&temp_hue)|\
card([$SELF:diff_hwc:col],"Energie Warmwasser","sani_water_tap",0,15,120,0,"kWh",undef,1)
Visualisierung: Anwesenheitsstatus
- FritzBox-Modul
- ui_Table Funktion icon_label
- uiTable-Templates
Die aktuelle Anwesenheit von Heimbewohnern wird visualisiert.
Zunächst wird mit Hilfe des Moduls FRITZBOX ein Device namens FritzBox erstellt. Dort werden die eingebuchten Smartphones der Bewohner mit Ihren MAC-Adressen in Readings abgelegt. Die folgende Definition wertet aus, ob die angegebenen MAC-Adressen als Readings vorhanden sind und erstellt für jeden Bewohner ein Reading mit den Zuständen on/off. Diese Readings werden dann über das Attribut uiTable visualisiert. Die anwesenden Personen werden farblich markiert. Die Namen der Personen sowie die MAC-Adressen sind fiktiv und müssen den eigenen Angaben entsprechend angepasst werden.
Ergebnis der Beispieldefinition in der Webansicht:

defmod myHome DOIF {\
set_Reading_Begin;;\
set_Reading_Update("Ernie",[FritzBox:mac_12_34_E0_00_CD_E4] ? "on":"off");;\
set_Reading_Update("Bert", [FritzBox:mac_02_08_02_07_30_E3] ? "on":"off");;\
set_Reading_Update("Grobi", [FritzBox:mac_00_08_01_0B_00_E7] ? "on":"off");; \
set_Reading_Update("Kermit", [FritzBox:mac_01_30_A9_72_02_E3] ? "on":"off");; \
set_Reading_End(1);;\
}
attr myHome checkReadingEvent 0
attr myHome uiTable {\
package ui_Table;;\
$SHOWNOSTATE=1;;\
$TC{0..4}="align='center'";;\
}\
## Template-Definition für die Visualisierung eines Bewohners mit Hilfe des Icons fa__508\
DEF TPL_person (icon_label([$SELF:$1] eq "on" ? "fa__508\@DarkOrange":"fa__508","$1","#e67e00","white",-10))\
\
## Darstellung der Bewohner mit Hilfe des obigen Templates\
TPL_person(Ernie)|TPL_person(Bert)|TPL_person(Grobi)|TPL_person(Kermit)
Ergebnis der Beispieldefinition in der Webansicht:

Visualisierung: Energiefluss als kompakte Energie-Karte
- svg-Funktion icon_ring2
Die vorgestellte Lösung visualisiert in kompakter Form den aktuellen Stromfluss des Hauses. Der Energiefluss wird abhängig von der Leistung und der Flussrichtung animiert. Die Definition muss an eigene Bedürfnisse angepasst werden. Dazu müssen die Variablen für die maximale Leistung am Anfang der Definition angepasst sowie im Attribut DOIF_Readings die eigenen Readings angegeben werden. Die Größe der Grafik ist über das CSS-Attribut zoom beliebig skalierbar (siehe im Device-Attribut uiTable Variable $TABLE). Im Definitionsbereich des DOIF-Devices sind alle erforderlichen Perlfunktionen definiert. Es wird vornehmlich die SVG-Funktion icon_ring2 des DOIF-Moduls benutzt. Im Attribut uiTable sind die einzelnen Visualisierungselemente als zuvor definierte Perlfunktionen angegeben. Falls der Batterie-Speicher nicht visualisiert werden soll, so können die beiden Zeilen beginnend mit "battery" gelöscht werden. Die programmierten Perlfunktionen können an eigene Bedürfnisse angepasst werden. So könnten z. B. ein E-Auto oder eine Wärmepumpe dargestellt werden. Es werden keine weiteren Perlfunktionen oder Javascripte außerhalb des DOIF-Devices benötigt. Vorausgesetzt wird die DOIF-Version: # $Id: 98_DOIF.pm 31131 2026-04-17 18:27:58Z Damian $ oder neuer.
Ergebnis der Beispieldefinition in der Webansicht:

defmod di_energy_card_compact DOIF subs {\
## Hier die eigenen Maximalwerte anpassen\
\
## Leistungangaben in kW, Werte können in der Realität überschritten werden \
$_grid_power_max=3.6;; # maximale Bezug/Einspeise-Leistung\
$_solar_power_max=3.6;; # maximale PV Leistung\
$_home_power_max=3.6;; # maximale Haus Leistung\
$_battery_power_max=1.0;; # maximale Lade/Entlade-Leistung\
\
## Tagesenergie in kWh, Werte können in der Realität überschritten werden \
$_grid_energy_feed_max=30;; # maximale Einspeiseenergie pro Tag\
$_grid_energy_consum_max=10;; # maximaler Bezugenergie pro Tag\
$_solar_energy_max=30;; # maximale PV Energie pro Tag\
$_home_energy_max=20;; # maximale Verbrauch pro Tag\
\
package ui_Table;;\
\
sub move {\
my ($left, $top, $content) = @_;;\
my $value;;\
if (ref($content) eq "ARRAY") {\
$value = $content->[0];;\
} else {\
$value =$content;;\
}\
\
my $out = '<div style="position:absolute;; left:'\
. $left . 'px;; top:'\
. $top . 'px;;">'\
. $value .\
'</div>';;\
\
if (ref($content) eq "ARRAY") {\
return ([$out,$content->[1]]);;\
} else {\
return ($out);;\
}\
}## end of move\
\
sub flow {\
\
my ($d,$item,$power,$max,$direction)=@_;;\
my $dur;;\
if ($power == 0) {\
$dur=0;;\
} else {\
$power=$max if ($power>$max);;\
$dur=6-abs(int(5*$power/$max));;\
}\
\
\
my ($from, $to, $x1, $x2, $y1, $y2);;\
\
if ($direction==0) { # ↖ unten rechts -> oben links\
($from, $to, $x1, $x2, $y1, $y2)=("1 1","-1 -1",100,0,100,0);;\
} elsif ($direction==1) { # ↘ oben links -> unten rechts\
($from, $to, $x1, $x2, $y1, $y2)=("-1 -1","1 1",0,100,0,100);;\
} elsif ($direction==2) { # ↗ unten links -> oben rechts\
($from, $to, $x1, $x2, $y1, $y2)=("-1 1","1 -1",0,100,100,0);;\
} elsif ($direction==3) { # ↙ oben rechts -> unten links\
($from, $to, $x1, $x2, $y1, $y2)=("1 -1","-1 1",100,0,0,100);;\
}\
\
my $out='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 35" width="40" height="35" style="width:40px;; height:35px;;">';;\
\
$out .= '<defs>\
<linearGradient id="flowGradient_'.$item.'" \
x1="'.$x1.'%" y1="'.$y1.'%" \
x2="'.$x2.'%" y2="'.$y2.'%" \
>\
<stop offset="0%" stop-color="white" stop-opacity="0.2"/>\
<stop offset="80%" stop-color="white" stop-opacity="1"/>\
<stop offset="100%" stop-color="white" stop-opacity="0.2"/>\
<animateTransform \
id="flowAnim_'.$item.'" \
attributeName="gradientTransform" \
type="translate" \
from="'.$from.'" \
to="'.$to.'" \
dur="'.$dur.'s" \
repeatCount="indefinite" \
calcMode="linear"/>\
</linearGradient>\
</defs>\
<path d="'.$d.'" fill="none" stroke="url(#flowGradient_'.$item.')" stroke-width="3" />';;\
\
return ([$out,'var e=document.getElementById("flowAnim_'.$item.'");;if (e) {e.setAttribute("dur","'.$dur.'s");;e.setAttribute("from","'.$from.'");;e.setAttribute("to","'.$to.'");;};; var e=document.getElementById("flowGradient_'.$item.'");;if (e) {e.setAttribute("x1","'.$x1.'%");;e.setAttribute("x2","'.$x2.'%");;e.setAttribute("y1","'.$y1.'%");;e.setAttribute("y2","'.$y2.'%");;}'])\
} ## end of flow'\
\
sub grid_power {\
my ($power)=@_;;\
return (move(30,64,flow("M 5 0 A 30 30 0 0 0 35 30","grid",$power,$_grid_power_max,($power > 0 ? 0 : 1))));;\
} \
\
sub solar_power {\
my ($power)=@_;;\
return move(138,64,flow("M 35 0 A 30 30 0 0 1 5 30 L 5 30","solar",$power,$_solar_power_max,3));;\
} \
\
sub home_power {\
my ($power)=@_;; \
return move(30,94,flow("M 5 35 A 30 30 0 0 1 35 5","home",$power,$_home_power_max,3));;\
}\
\
sub battery_power {\
my ($power)=@_;;\
return move(138,94,flow("M 35 35 A 30 30 0 0 0 5 5 ","battery",$power,$_battery_power_max,($power < 0 ? 0:1)));;\
}\
\
sub grid {\
my ($power,$feed,$consum)=@_;;\
\
move(2,2,icon_ring2("scene_power_grid\@silver",$power,-$_grid_power_max,$_grid_power_max,undef,undef,"kW",110,[(-0.33*$_grid_power_max,20,-0.01,40,0.33*$_grid_power_max,65,$_grid_power_max,85)],"2",$feed-$consum,-$_grid_energy_feed_max,$_grid_energy_feed_max,0,90,"kWh",undef,"1",undef,"nogradient,,innerring,nopointer,negzeropos"));;\
}\
\
sub self {\
my ($autark,$EVG)=@_;;\
move(64,60,ring2($autark,0,100,undef,undef,"Autarkie",130,[(33.3,40,66.6,65,100,85)],"0,,fill:silver, %",$EVG,0,100,190,170,"EVQ",undef,"0,,fill:silver, %",undef,undef,"nogradient,,innerring,nopointer")) # [(33.3,40,66.6,65,100,85)]\
}\
\
sub solar {\
my ($power,$energy)=@_;;\
\
my ($power,$energy,$self_energy)=@_;; \
move(140,2,icon_ring2("solar_icon\@silver",$power,0,$_solar_power_max,60,90,"kW",110,undef,"2",$energy,0,$_solar_energy_max,60,90,"kWh",undef,"1",undef,"nogradient,,noinnerring,nopointer"));;\
}\
\
sub home {\
my ($power,$consum)=@_;;\
move(2,130,icon_ring2("fa_home\@silver",$power,0,$_home_power_max,40,10,"kW",110,undef,"2",$consum,0,$_home_energy_max,40,10,"kWh",undef,"1",undef,"nogradient,,noinnerring,nopointer"));;\
}\
\
sub battery {\
my ($power,$cap)=@_;;\
move(140,130,icon_ring2("battery_100\@silver",$power,-$_battery_power_max,,$_battery_power_max,220,170,"kW",110,[(-0.0001,200,$_battery_power_max,160)],"2",$cap,0,100,0,90,"%",undef,"0",undef,"nogradient,,innerring,nopointer,negzeropos"));;\
}\
}
attr di_energy_card_compact DOIF_Readings grid_power: [Netz:Leistung_Einspeisung_Bezug] ## Leistung Netz Einspeisung kW negativ Bezug kW,\
grid_energy_feed: [Netz:Energie_Einspeisung] ## Energie Einspeisung kWh,\
grid_energy_consum: [Netz:Energie_Bezug] ## Energie Bezug kWh,\
solar_power: [PV:Leistung_PV] ## Leistung PV kW,\
solar_energy: [PV:Energie_PV] ## Energie des Tages PV kWh,\
home_power: ([Haus:Leistung_Verbrauch]) ## Leistung Haus kW,\
home_energy: [Haus:Energie_Verbrauch] ## Energie Haus kWh,\
battery_power: [Speicher:Leistung] ## Leistung Speicher kW laden positiv entladen negativ,\
battery_capa: [Speicher:Kapazität] ## Kapazität Speicher %,\
autarchy:([Energie:Autarkie] ## Autarkie %,\
scr: [Energie:Eigenverbrauchquote] ## Eigenverbrauchsquote %
attr di_energy_card_compact uiTable {\
$ATTRIBUTESFIRST = 1;;\
\
## Energy_card kann über das Attribut zoom skaliert werden\
\
$TABLE = 'zoom: 1;; width: 212px;; height: 195px;; text-align: left;; vertical-align: top;; border-radius:0%;; position:relative;; background: linear-gradient(to bottom, rgb(40,40,40), rgb(60, 60, 60));; ';;\
\
package ui_Table;;\
\
} ## end of perl area\
\
## Tabellendefinition\
## nicht benötigte Darstellungselemente können Zeilenweise gelöscht werden\
\
grid([$SELF:grid_power],[$SELF:grid_energy_feed],[$SELF:grid_energy_consum]).\
grid_power([$SELF:grid_power]).\
solar([$SELF:solar_power],[$SELF:solar_energy]).\
solar_power([$SELF:solar_power]).\
battery([$SELF:battery_power],[$SELF:battery_capa]).\
battery_power([$SELF:battery_power]).\
home ([$SELF:home_power],[$SELF:home_energy]).\
home_power([$SELF:home_power]).\
self([$SELF:autarchy],[$SELF:scr])
Visualisierung: Energiefluss als Energie-Karte
- svg-Funktion card
Hier wird eine Version der Energie-Karte mit Hilfe der SVG-Funktion card des DOIF-Moduls realisiert. In dieser Darstellung wird zusätzlich der Verlauf der jeweiligen Leistungen und der Speicherkapazität visualisiert. Die Konfiguration bzw. Anpassung an eigene Bedürfnisse sind wie bei der kompakten Energie-Karte oben vorzunehmen. Sollten beide Version gleichzeitig genutzt werden wollen, dann müssen die programmierten Perlfunktionen einer Version umbenannt werden, sonst überschreiben sie sich gegenseitig, weil sie im gleichen Package liegen.
Ergebnis der Beispieldefinition in der Webansicht:

defmod di_energy_card DOIF subs {\
## Leistungangaben in kW, \
$_grid_power_max=3.6;; # maximale Bezug/Einspeise-Leistung\
$_solar_power_max=3.6;; # maximale PV Leistung\
$_home_power_max=3.6;; # maximale Haus Leistung\
$_battery_power_max=1.050;; # maximale Lade/Entlade-Leistung\
## Tagesenergie in kWh, Werte können überschritten werden\
$_grid_energy_feed_max=30;; # maximale Einspeiseenergie pro Tag\
$_grid_energy_consum_max=10;; # maximaler Bezugenergie pro Tag\
$_solar_energy_max=30;; # maximale PV Energie pro Tag\
$_home_energy_max=20;; # maximale Verbrauch pro Tag\
\
package ui_Table;;\
\
sub move {\
my ($left, $top, $content) = @_;;\
my $value;;\
if (ref($content) eq "ARRAY") {\
$value = $content->[0];;\
} else {\
$value =$content;;\
}\
\
my $out = '<div style="position:absolute;; left:'\
. $left . 'px;; top:'\
. $top . 'px;;">'\
. $value .\
'</div>';;\
\
if (ref($content) eq "ARRAY") {\
return ([$out,$content->[1]]);;\
} else {\
return ($out);;\
}\
}## end of move\
\
sub flow {\
\
my ($d,$item,$power,$max,$direction)=@_;;\
my $dur;;\
if ($power == 0) {\
$dur=0;;\
} else {\
$power=$max if ($power>$max);;\
$dur=6-abs(int(5*$power/$max));;\
}\
\
\
my ($from, $to, $x1, $x2, $y1, $y2);;\
\
if ($direction==0) { # ↖ unten rechts -> oben links\
## ($from, $to, $x1, $x2, $y1, $y2)=("1 1","-1 -1",101,-1,100,0);;\
($from, $to, $x1, $x2, $y1, $y2)=("1 1","-1 -1",100,0,0,0);;\
} elsif ($direction==1) { # ↘ oben links -> unten rechts\
## ($from, $to, $x1, $x2, $y1, $y2)=("-1 -1","1 1",-1,101,0,100);; \
($from, $to, $x1, $x2, $y1, $y2)=("-1 -1","1 1",0,97,0,0);;\
} elsif ($direction==2) { # ↗ unten links -> oben rechts\
($from, $to, $x1, $x2, $y1, $y2)=("-1 1","1 -1",-1,101,1,0);;\
} elsif ($direction==3) { # ↙ oben rechts -> unten links\
## ($from, $to, $x1, $x2, $y1, $y2)=("1 -1","-1 1",101,-1,0,100);;\
($from, $to, $x1, $x2, $y1, $y2)=("1 1","-1 -1",100,0,3,0);;\
}\
\
my $out='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 35" width="90" height="35" style="width:90px;; height:35px;;">';;\
\
$out .= '<defs>\
<linearGradient id="flowGradient_'.$item.'" \
x1="'.$x1.'%" y1="'.$y1.'%" \
x2="'.$x2.'%" y2="'.$y2.'%" \
>\
<stop offset="0%" stop-color="white" stop-opacity="0.2"/>\
<stop offset="90%" stop-color="white" stop-opacity="1"/>\
<stop offset="100%" stop-color="white" stop-opacity="0.2"/>\
<animateTransform \
id="flowAnim_'.$item.'" \
attributeName="gradientTransform" \
type="translate" \
from="'.$from.'" \
to="'.$to.'" \
dur="'.$dur.'s" \
repeatCount="indefinite" \
calcMode="linear"/>\
</linearGradient>\
</defs>\
<path d="'.$d.'" fill="none" stroke="url(#flowGradient_'.$item.')" stroke-width="3" />';;\
\
return ([$out,'var e=document.getElementById("flowAnim_'.$item.'");;if (e) {e.setAttribute("dur","'.$dur.'s");;e.setAttribute("from","'.$from.'");;e.setAttribute("to","'.$to.'");;};; var e=document.getElementById("flowGradient_'.$item.'");;if (e) {e.setAttribute("x1","'.$x1.'%");;e.setAttribute("x2","'.$x2.'%");;e.setAttribute("y1","'.$y1.'%");;e.setAttribute("y2","'.$y2.'%");;}'])\
} ## end of flow'\
\
sub grid_power {\
my ($power)=@_;;\
return (move(110,149,flow("M 5 0 A 30 30 0 0 0 35 30 L 90 30","grid",$power,$_grid_power_max,($power > 0 ? 0 : 1))));;\
} \
\
sub solar_power {\
my ($power)=@_;;\
return move(274,149,flow("M 85 0 A 30 30 0 0 1 55 30 L 0 30","solar",$power,$_solar_power_max,3));;\
} \
\
sub home_power {\
my ($power,$max)=@_;; \
return move(110,185,flow("M 5 35 A 30 30 0 0 1 35 5 L 90 5","home",$power,$_home_power_max,3));;\
}\
\
sub battery_power {\
my ($power)=@_;;\
return move(274,185,flow("M 85 35 A 30 30 0 0 0 55 5 L 0 5","battery",$power,$_battery_power_max,($power < 0 ? 0:1)));;\
}\
\
sub grid {\
my ($power,$feed,$consum)=@_;;\
move(2,2,card($power,"Netz","scene_power_grid\@silver",-$_grid_power_max,$_grid_power_max,undef,undef,"kW",[(-0.33*$_grid_power_max,20,-0.01,40,0.33*$_grid_power_max,65,$_grid_power_max,85)],"3","130,autoscaling,steps,footer,noycolor,ring,180","nogradient,,innerring,nopointer,negzeropos",undef, [[$feed,0,$_grid_energy_feed_max,60,90,"Einsp.",undef],[$consum,0,$_grid_energy_consum_max,40,10,"Bezug",undef]],0,0,undef,undef,["",""],undef,"1,,fill:silver, kWh"));;\
}\
\
\
sub self {\
my ($autark,$EVG)=@_;;\
move(200,151,ring2($autark,0,100,undef,undef,"Autarkie",120,[(33.3,40,66.6,65,100,85)],"0,,fill:silver, %",$EVG,0,100,190,170,"EVQ",undef,"0,,fill:silver, %",undef,undef,"nogradient,,innerring,nopointer"))\
}\
sub solar { \
my ($power,$energy,$self_energy)=@_;; move(237,2,card($power,"PV","solar_icon\@silver",0,$_solar_power_max,60,90,"kW",undef,"3,,,","130,autoscaling,steps,footer,noycolor,ring,180","nogradient,,innerring,nopointer",undef, [$self_energy,$energy],0,$_solar_energy_max,60,90,["Eigen.","Erzeug."],undef,"1,,fill:silver, kWh"))\
}\
\
sub home {\
my ($power,$consum)=@_;; move(2,222,card($power,"Haus","fa_home\@silver",0,$_home_power_max,40,10,"kW",undef,"3,,,","130,autoscaling,steps,footer,noycolor,ring,180","nogradient,,innerring,nopointer,negzeropos",undef, [[$consum]],0,$_home_energy_max,40,10,[""],undef,"1,,, kWh"));;\
}\
\
sub battery {\
my ($power,$Cap)=@_;;\
move(237,222,card($power,"Speicher","battery_100\@silver",-$_battery_power_max,$_battery_power_max,undef,undef,"kW",[(-0.0001,200,$_battery_power_max,160)],"3,,,","130,fixedscaling,steps,footer,noycolor,ring,180","1,,1,0,negzeropos",undef,[$Cap],0,100,0,90,"Kapaz.",undef,"0,,fill:silver, %"))\
}\
}
attr di_energy_card_compact DOIF_Readings grid_power: [Netz:Leistung_Einspeisung_Bezug] ## Leistung Netz Einspeisung kW negativ Bezug kW,\
grid_energy_feed: [Netz:Energie_Einspeisung] ## Energie Einspeisung kWh,\
grid_energy_consum: [Netz:Energie_Bezug] ## Energie Bezug kWh,\
solar_power: [PV:Leistung_PV] ## Leistung PV kW,\
solar_energy: [PV:Energie_PV] ## Energie des Tages PV kWh,\
solar_self_energy: [PV:Energie_PV]-[Netz:Energie_Bezug] ## Eigenverbrauch PV kWh,\
home_power: ([Haus:Leistung_Verbrauch]) ## Leistung Haus kW,\
home_energy: [Haus:Energie_Verbrauch] ## Energie Haus kWh,\
battery_power: [Speicher:Leistung] ## Leistung Speicher kW laden positiv entladen negativ,\
battery_capa: [Speicher:Kapazität] ## Kapazität Speicher %,\
autarchy:([Energie:Autarkie] ## Autarkie %,\
scr: [Energie:Eigenverbrauchquote] ## Eigenverbrauchsquote %
attr di_energy_card uiTable {\
$ATTRIBUTESFIRST = 1;;\
\
## Energy_card kann über das Attribut zoom skalliert werden\
\
$TABLE = 'zoom: 1;; width: 473px;; height: 384px;; text-align: left;; vertical-align: top;; border-radius:0%;; position:relative;; background: linear-gradient(to bottom, rgb(40,40,40), rgb(60, 60, 60));; ';;\
\
package ui_Table;;\
\
} ## end of perl area\
\
## Tabellendefinition\
## nicht benötigte Darstellungselemente können Zeilenweise gelöscht werden\
\
grid([$SELF:grid_power:144col1d],[$SELF:grid_energy_feed],[$SELF:grid_energy_consum]).\
grid_power([$SELF:grid_power]).\
solar([$SELF:solar_power:144col1d],[$SELF:solar_energy],[$SELF:solar_self_energy]).\
solar_power([$SELF:solar_power]).\
battery([$SELF:battery_power:144col1d],[$SELF:battery_capa:144col1d]).\
battery_power([$SELF:battery_power]).\
home ([$SELF:home_power:144col1d],[$SELF:home_energy]).\
home_power([$SELF:home_power]).\
self([$SELF:autarchy],[$SELF:scr])
Weiterführende Links
- DOIF/uiTable_Schnelleinstieg
- DOIF/Perl-Modus
- DOIF/Automatisierung
- Weitere Beispiele für Fortgeschrittene, siehe "uiTable mit FHEM-Widgets und Styles"