Zum Inhalt springen

DOIF/uiTable Anwendung

Aus FHEMWiki
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Visualisierung und Steuerung von Rollläden

nützliche Links

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.





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)\

Ergebnis des Anwendungsbeispiels in der Webansicht:

Anzahl der Tage bis zur Abfall-Entsorgung

nützliche Links

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.

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)|)

Ergebnis der Beispieldefinition in der Webansicht:

Visualisierung: offene Fenster

nützliche Links

Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert.

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]

Ergebnis der Beispieldefinition in der Webansicht:

Visualisierung: aktuelle Wetterlage

nützliche Links

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.



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>"\

Ergebnis der Beispieldefinition in der Webansicht:


Visualisierung: Wetterstation

nützliche Links

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.

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)

Ergebnis der Beispieldefinition in der Webansicht:


Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion card:

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)

Ergebnis der Beispieldefinition in der Webansicht:


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


Visualisierung: aktueller Spritpreis

nützliche Links

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.




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

Ergebnis der Beispieldefinition in der Webansicht:

Visualisierung der Preisentwicklung der letzten 24 Stunden:

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)

Ergebnis der Beispieldefinition in der Webansicht:

Visualisierung: aktuelle Corona-7-Tage-Inzidenz

nützliche Links

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.



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")

Ergebnis der Beispieldefinition in der Webansicht:


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.

nützliche Links

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.

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)

Ergebnis der Beispieldefinition in der Webansicht:


Visualisierung: Anwesenheitsstatus

nützliche Links

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.

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

nützliche Links

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 ring2-SVG-Funktion 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.

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,\
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_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])

Ergebnis der Beispieldefinition in der Webansicht:

Weiterführende Links