ReadingsGroup: Unterschied zwischen den Versionen

Aus FHEMWiki
(Änderung 31300 von FExplorer (Diskussion) rückgängig gemacht. ° ist korrekt wenn man nicht mit utf-8 arbeitet.)
Markierung: Rückgängigmachung
 
(89 dazwischenliegende Versionen von 19 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{SEITENTITEL:readingsGroup}}
{{SEITENTITEL:readingsGroup}}
{{Infobox Modul
{{Infobox Modul
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung
|ModType=h
|ModType=h
<!-- |ModCategory= (noch?) nicht verwendet -->
|ModCmdRef=readingsGroup
|ModCmdRef=readingsGroup
|ModForumArea=Frontends
|ModTechName=33_readingsGroup.pm
|ModTechName=33_readingsGroup.pm
|ModOwner=[http://forum.fhem.de/index.php?action=profile;u=430 Andre / justme1968]}}
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}
Das Fhem-[[:Kategorie:Hilfsmodul|Hilfsmodul]] [[readingsGroup]] bietet eine einfache Möglichkeit, ''readings'' und ''internal values'' von einem oder mehreren ''Devices'' darzustellen und flexibel zu formatieren.


Hier soll eine Sammlung von Beispielen zur Verwendung der ''readingsGroup'' mitsamt der zugehörigen Screenshots entstehen.
Das FHEM-[[:Kategorie:Hilfsmodul|Hilfsmodul]] [[readingsGroup]] bietet eine einfache Möglichkeit, <code>Readings</code> (kein Präfix vor dem Reading-Namen), <code>Internals</code> (Präfix "+" vor dem Namen des internen Wertes) und <code>Attributes</code> (Präfix "?" vor dem Namen des Attributs) von einem oder mehreren <code>Devices</code> darzustellen und flexibel zu formatieren.
 
Die Aktualisierung im Browserfenster geschieht per <code>longpoll</code> und überträgt nur die jeweils geänderten Zellen. Wenn eine <code>readingsGroup</code> in keinem Browserfenster angezeigt wird, findet keine <code>longpoll</code> Aktualisierung statt.


== Definition ==  
== Definition ==  
Siehe commandref.
Siehe {{Link2CmdRef|Anker=readingsGroup}}.


== Attribute ==
== Attribute ==
Weitergehende Erläuterungen zu einzelnen Attributen:
{{Randnotiz|RNText=In allen Mappings die einen Hash verwenden muss der Key (das was jeweils links von => Operator steht) in Anführungszeichen stehen. Die einzige Ausnahme hiervon sind Keys die aus einem String bestehen der mit einem Buchstaben beginnt und nur Buchstaben und Zahlen enthält.}}
Weitergehende Erläuterungen zu einzelnen Attributen.
 
Die komplette Liste der Attribute ist der {{Link2CmdRef}} zu entnehmen.


=== noheading ===
=== noheading ===
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]
Das Attribut <code>noheading</code> führt dazu, dass der Alias der ReadingsGroup nicht mehr als Titel angezeigt wird. Das kann wünschenswert sein, wenn die ReadingsGroup auf einer [[Dashboard]]-Seite angezeigt werden soll, hat allerdings den Nachteil, dass die Detail-Ansicht der ReadingsGroup nicht mehr über einen Klick auf den Titel aufgerufen werden kann. Der Einstellungsdialog der ReadingsGroup ist dann nur noch (z.&nbsp;B.) über
Das Attribut <code>noheading</code> führt dazu, dass der Alias der ReadingsGroup nicht mehr als Titel angezeigt wird. Das kann wünschenswert sein, wenn die ReadingsGroup auf einer [[Dashboard]]-Seite angezeigt werden soll, hat allerdings den Nachteil, dass die Detail-Ansicht der ReadingsGroup nicht mehr über einen Klick auf den Titel aufgerufen werden kann. Der Einstellungsdialog der ReadingsGroup ist dann nur noch (z.&nbsp;B.) über
* <code>list TYPE=readingsGroup</code>
* einen "Probably associated with"-Link eines anderen Objekts oder über
* einen "Probably associated with"-Link eines anderen Objekts oder über
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)
erreichbar.
erreichbar.
=== nolinks ===
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.
=== nostate ===
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.
=== notime ===
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.
=== mapping ===
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um
* den Zeilentitel gegen den Raumnamen auszutauschen (z.B. [[ReadingsGroup#Einfache Auswahl über Reading-Namen|einfach]], [[ReadingsGroup#Schriftgrößen, Farben, Icons|doppelt]], [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|erweitert]], [[ReadingsGroup#Heizungsteuerung für HM Wand- und Heizkörperthermostate|noch mehr]], [[ReadingsGroup#Enigma Receiver|leer]])
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der {{Link2CmdRef}}.
=== valueFormat ===
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (z.B. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (z.B. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])
* unerwünschte Werte auszufiltern (z.B. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (z.B. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]])
* größere Berechnungen in [[99_myUtils_anlegen|99_myUtils.pm]] aufzurufen (z.B. [[ReadingsGroup#Enigma Receiver|Enigma Receiver]]).
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der {{Link2CmdRef}}.
=== valueIcon ===
valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (z.B. [[ReadingsGroup#Auswahl über Reading-Namen, Status als Symbol dargestellt|einfach]], [[ReadingsGroup#Heizungswerte, Status und Regelmöglichkeit|etwas mehr]]).
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der {{Link2CmdRef}}.
=== valueStyle ===
valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (z.B. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)|einfach]], [[ReadingsGroup#Internal Values ausgeben|erweitert]], [[ReadingsGroup#Wertabhängige Farbgebung|komplex]]).
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der {{Link2CmdRef}}.


== Beispiele ==
== Beispiele ==
Achtung: Die Beispiele enthalten keine Maskierungen oder Verdoppelungen für ; und Zeilenende, sondern sind so angegeben, wie sie in Fhemweb, in der command box oder nach Klick auf DEF eingegeben werden. Beim manuellen Einfügen in eine [[Konfiguration|Konfigurationsdatei]] sind diese Maskierungen oder Verdoppelungen natürlich vorzunehmen.
Bitte beachten: die folgenden Beispiele enthalten keine Maskierungen oder Verdoppelungen für ; und Zeilenende, sondern sind so angegeben, wie sie im [[PGM2|Web Interface]] im Befehls-Eingabefeld, nach Klick auf DEF und im Attribut-Eingabefeld eingegeben werden. Beim manuellen Einfügen in eine [[Konfiguration|Konfigurationsdatei]] sind diese Maskierungen oder Verdoppelungen natürlich vorzunehmen.


=== Einfache Auswahl über Reading-Namen ===
=== Einfache Auswahl über Reading-Namen ===
Zeile 41: Zeile 79:
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.
|}
|}
=== Übersicht HomeMatic Geräte ===
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki>


=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===
Zeile 100: Zeile 142:
! Definition !! Erläuterungen !! Aussehen  
! Definition !! Erläuterungen !! Aussehen  
|-
|-
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_baraometric_pressure>,<Luftdruck>,pressure
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure
</code>
</code>
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.
Zeile 113: Zeile 155:


=== Internal Value ausgeben ===
=== Internal Value ausgeben ===
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).
Dieses Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).
{| class="wikitable"
{| class="wikitable"
! Definition !! Erläuterungen !! Aussehen  
! Definition !! Erläuterungen !! Aussehen  
|-
|-
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code>
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code>
| Den cul_RSSI Wert aller Devices die einen solchen haben anzeigen.<br> '''Achtung''': "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.
| Den RSSI Wert aller Devices (am IODev ''cul'') die einen solchen haben anzeigen.<br> '''Achtung''': "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]
|}
|}
Zeile 127: Zeile 169:
|-
|-
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code>
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code>
| Den cul_RSSI Wert mit der zugehörigen Zeit aller Devices die einen solchen haben anzeigen.<br> '''Achtung''': "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.<br>"Internal Values" werden durch das vorangestellte '''+''' (Pluszeichen) identifiziert.
| Den RSSI Wert mit der zugehörigen Zeit aller Devices (am IODev ''cul'') die einen solchen haben anzeigen.<br> '''Achtung''': "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.<br>"Internal Values" werden durch das vorangestellte '''+''' (Pluszeichen) identifiziert.
| rowspan=1 | [[Datei:rgculRSSI2.png|thumb]]
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]
|-
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).
|}
|}


Zeile 155: Zeile 200:
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code>
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code>
| Die Temperatur readings der Devices t1, t2 und t3
| Die Temperatur readings der Devices t1, t2 und t3
| rowspan=6 | [[Datei:rgHeizung.png|thumb]]
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]
|-
|-
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code>
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code>
Zeile 171: Zeile 216:
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code>
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code>
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit
|}
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===
{| class="wikitable"
! Definition !! Erläuterungen !! Aussehen
|-
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code>
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.
| rowspan=6 |
|-
| <code>attr lcDropDown commands { state => 'scene:' }</code>
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.
|-
| <code>attr lcDropDown nonames 1</code>
| Keine Readingnamen
|-
| <code>attr lcDropDown notime 1</code>
| Kein Timestamp
|}
|}


Zeile 266: Zeile 331:
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.
|-
|-
| <code>
|<syntaxhighlight lang="perl">
sub wzReceiverRGvalueFormat($$$)
sub
{
wzReceiverRGvalueFormat($$$)
  my ($DEVICE,$READING,$VALUE) = @_;
{
  my ($DEVICE,$READING,$VALUE) = @_;
   
   
  if($READING eq 'hdd1_capacity') {  
  if($READING eq 'hdd1_capacity') {  
    return "%.2f MB";
    return "%.2f MB";
  } elsif( $READING eq 'hdd1_free') {
  } elsif( $READING eq 'hdd1_free') {
    return "%.2f MB";
    return "%.2f MB";
  } elsif( $READING eq 'volume' ) {
  } elsif( $READING eq 'volume' ) {
    if( ReadingsVal($DEVICE, "mute", "") eq "on") {
    if( ReadingsVal($DEVICE, "mute", "") eq "on") {
      return "mute";
      return "mute";
    } else {
    } else {
      return "%i %%";
      return "%i %%";
    }
    }
  }
  }
}</code>
}</syntaxhighlight>
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]
|}
|}
Zeile 311: Zeile 377:
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]
|-
|-
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,<Ventil>,<Soll>,<Ist>,<MaxV>,<GID>,<Mode>,<Batterie> type=CUL_HM:ValvePosition,desired-tempe,measured-temp,R-valveMaxPos,groupid,mode,battery</code>
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,<Ventil>,<Soll>,<Ist>,<MaxV>,<GID>,<Mode>,<Batterie> TYPE=CUL_HM:ValvePosition,desired-temp,measured-temp,R-valveMaxPos,groupid,mode,battery</code>
| Diverse readings aller Devices des Typs <b>MAX</b>.  
| Diverse readings aller Devices des Typs <b>MAX</b>.  
|-
|-
Zeile 321: Zeile 387:
|-
|-
| <code>attr Heizungswerte room Heizung</code>
| <code>attr Heizungswerte room Heizung</code>
| Die "readingsgroup" wird dem Ruam "Heizung" zugeordnet.
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.
|-
|-
| <code>attr Heizungswerte valueFormat {temperature => "%.0f °C", desiredTemperature => "%.0f °C", valveposition =>"%.0f %%",maxValveSetting =>"%.0f %%" }</code>
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code>
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.
|-
|-
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code>
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code>
| Für den Batterzustand werden Icons anstatt Klartextwerte genommen!
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!
|-
|-
| <code>attr Heizungswerte valueStyle { if($READING eq "temperature" && $VALUE > 20){ 'style="color:green;;font-weight:bold"' }elsif( $READING eq "temperature" && $VALUE <= 20 ){ 'style="color:blue"' }elsif( $READING eq "temperature" && $VALUE > 23 ){ 'style="color:red"' }else{ 'style="color:gray"' } }</code>
| <code>attr Heizungswerte valueStyle { if($READING eq "temperature" && $VALUE > 20){ 'style="color:green;;font-weight:bold"' }elsif( $READING eq "temperature" && $VALUE <= 20 ){ 'style="color:blue"' }elsif( $READING eq "temperature" && $VALUE > 23 ){ 'style="color:red"' }else{ 'style="color:gray"' } }</code>
Zeile 335: Zeile 401:
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.
|}
|}


=== Heizungswerte, Status und Regelmöglichkeit ===
=== Heizungswerte, Status und Regelmöglichkeit ===
Zeile 355: Zeile 420:
| Nach dem Einstellen den Wert wieder ausblenden.  
| Nach dem Einstellen den Wert wieder ausblenden.  
|-
|-
| <code>
| <syntaxhighlight lang="perl">
#Heizung regeln in readingsGroup
#Heizung regeln in readingsGroup
sub
sub
myUtils_HeizungUpDown($$)
myUtils_HeizungUpDown($$)
{
{
  my($DEVICE,$CMD) = @_;
  my($DEVICE,$CMD) = @_;
    
    
  my $icon = $CMD;
  my $icon = $CMD;
  my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );
  my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );
  $VALUE = ReadingsVal($DEVICE,"desired-temp","20" )
  $VALUE = ReadingsVal($DEVICE,"desired-temp","20" )
      if( !$VALUE || $VALUE == 0 );
    if( !$VALUE || $VALUE == 0 );
  my $link;
  my $link;
    
    
  if( $CMD eq "up" ) {
  if( $CMD eq "up" ) {
    $icon = "control_arrow_upward";
    $icon = "control_arrow_upward";
    $VALUE += 1;
    $VALUE += 1;
    
    
    if( $VALUE <= 24 ) {
    if( $VALUE <= 24 ) {
      $icon .= "\@red";
      $icon .= "\@red";
      $link = "setreading $DEVICE desired-new $VALUE";
      $link = "setreading $DEVICE desired-new $VALUE";
    }
    }
  } elsif( $CMD eq "down" ) {
  } elsif( $CMD eq "down" ) {
    $icon = "control_arrow_downward";
    $icon = "control_arrow_downward";
    $VALUE -= 1;
    $VALUE -= 1;
    
    
    if( $VALUE >= 18 ) {
    if( $VALUE >= 18 ) {
      $icon .= "\@blue";
      $icon .= "\@blue";
      $link = "setreading $DEVICE desired-new $VALUE";
      $link = "setreading $DEVICE desired-new $VALUE";
    }
    }
  }
  }
    
    
  my $notify = "notifyHeizungUpDown";
  my $notify = "notifyHeizungUpDown";
  if( !defined($defs{$notify}) ) {
  if( !defined($defs{$notify}) ) {
    CommandDefine(undef,
    CommandDefine(undef,
                    "$notify notify .*:desired-new.* "
                  "$notify notify .*:desired-new.* "
                    ."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );
                  ."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );
  }
  }
    
    
  my $ret = "%$icon";
  my $ret = "%$icon";
  $ret .= "%$link" if( $link );
  $ret .= "%$link" if( $link );
    
    
  return $ret;
  return $ret;
}
}
sub
 
myUtils_HeizungUpDownNotify($$)
sub
{
myUtils_HeizungUpDownNotify($$)
  my($DEVICE,$VALUE) = @_;
{
  my($DEVICE,$VALUE) = @_;
    
    
  return if( $VALUE == 0 );
  return if( $VALUE == 0 );
    
    
  my $at = "triggerHeizungUpDown_$DEVICE";
  my $at = "triggerHeizungUpDown_$DEVICE";
  CommandDelete(undef, $at) if( defined($defs{$at}) );
  CommandDelete(undef, $at) if( defined($defs{$at}) );
  CommandDefine(undef,
  CommandDefine(undef,
                  "$at at +00:00:03 "
                "$at at +00:00:03 "
                  ."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"
                ."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"
                  ."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"
                ."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"
                  ."fhem(\"setreading $DEVICE desired-new 00\");}" );
                ."fhem(\"setreading $DEVICE desired-new 00\");}" );
    
    
  return undef;
  return undef;
  }
}</syntaxhighlight>
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hiermit werden die Icons zum Ändern der gewünschten Temperatur dargestellt und im Bereich >=18 und <= 24 Grad anklickbar gemacht. Zwischen den Pfeilen wird der gerade eingestellte Wert angezeigt. Wenn dieser drei Sekunden nicht mehr geändert wurde wird die desired-temp auf diesen Wert gesetzt und die Anzeige zwischen den Pfeilen ausgeblendet.
|}
 
=== Heizungswerte, Status, Steuerung und Wochenprofil ===
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.
{{Todo|Überarbeiten: umstellen auf readingList oder setreading, label als readings in die readingsGroup selber stecken statt in einen extra dummy. oder !<reading> und mapping verwenden.}}
{| class="wikitable"
! Definition !! Erläuterungen
|-
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]
|-
| style="width:40%" |<pre>
define d_label dummy
setreading d_label Heizung Heizung
setreading d_label Temperatur Temperatur
setreading d_label  Status Status
setreading d_label Wochenplan Wochenplan
setreading d_label Werktag Werktag
setreading d_label Samstag Samstag
setreading d_label Sonntag Sonntag
setreading d_label Zeitraum1 Zeitraum 1
setreading d_label Zeitraum2 Zeitraum 2 </pre>
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)
|-
| <code>
define rg_thermostate readingsGroup <>,Heizung@d_label,<|>,Temperatur@d_label,<|>,Status@d_label,<|>,Wochenplan@d_label,<|>,Werktag@d_label,<|>,Samstag@d_label,<|>,Sonntag@d_label,<|>,<> CUL_HM_HM_CC_RT_DN_......_Clima:<>,?alias,<|>,<Soll>,desired-temp,<Tag>,dayTemp@{rg($DEVICE."§clima")},impossible@{$DEVICE},<|>,controlMode,R-globalBtnLock@{rg($DEVICE."§device")},<|>,Zeitraum1@d_label,<|>,workday_period_1_start@{rg($DEVICE."§clima")},workday_period_1_stop@{rg($DEVICE."§clima")},<|>,saturday_period_1_start@{rg($DEVICE."§clima")},saturday_period_1_stop@{rg($DEVICE."§clima")},<|>,sunday_period_1_start@{rg($DEVICE."§clima")},sunday_period_1_stop@{rg($DEVICE."§clima")},<|>,impossible@{$DEVICE},<%system_fhem_update>,<nowiki><br></nowiki>,state@{rg($DEVICE."§device")},<%getConfig>,<|>,<Ist>,measured-temp,<Nacht>,nightTemp@{rg($DEVICE."§clima")},<|>,<Ventil>,ValvePosition,<|>,Zeitraum2@d_label,<|>,workday_period_2_start@{rg($DEVICE."§clima")},workday_period_2_stop@{rg($DEVICE."§clima")},<|>,saturday_period_2_start@{rg($DEVICE."§clima")},saturday_period_2_stop@{rg($DEVICE."§clima")},<|>,sunday_period_2_start@{rg($DEVICE."§clima")},sunday_period_2_stop@{rg($DEVICE."§clima")},<|>,impossible@{$DEVICE},impossible@{rg($DEVICE."§device")},<%burstXmit> </code>
| Diverse readings aller Devices <b>CUL_HM_HM_CC_RT_DN_......_Clima</b>, entsprechender [[Makefine#d_climaControl|d_climaControl]] (müssen vorher angelegt werden) und [[dummy#d_label|d_label]].
|-
| <code>attr rg_thermostate commands { 'desired-temp' => 'desired-temp:', 'dayTemp' => 'dayTemp:', 'controlMode' => 'trigger ntfy_rg $DEVICE controlMode', 'R-globalBtnLock' => 'trigger ntfy_rg $DEVICE globalBtnLock', 'workday_period_1_start' => 'workday_period_1_start:', 'workday_period_1_stop' => 'workday_period_1_stop:', 'saturday_period_1_start' => 'saturday_period_1_start:', 'saturday_period_1_stop' => 'saturday_period_1_stop:', 'sunday_period_1_start' => 'sunday_period_1_start:', 'sunday_period_1_stop' => 'sunday_period_1_stop:', 'rg_thermostate.system_fhem_update' => 'trigger ntfy_rg $DEVICE setTimeTable', 'rg_thermostate.getConfig' => 'set $DEVICE getConfig', 'nightTemp' => 'nightTemp:', 'workday_period_2_start' => 'workday_period_2_start:', 'workday_period_2_stop' => 'workday_period_2_stop:', 'saturday_period_2_start' => 'saturday_period_2_start:', 'saturday_period_2_stop' => 'saturday_period_2_stop:', 'sunday_period_2_start' => 'sunday_period_2_start:', 'sunday_period_2_stop' => 'sunday_period_2_stop:', 'rg_thermostate.burstXmit' => 'set $DEVICE burstXmit'}</code>
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]
|-
| <code>attr rg_thermostate mapping { 'desired-temp' => '', 'dayTemp' => '', 'workday_period_1_start' => '', 'workday_period_1_stop' => '', 'saturday_period_1_start' => '', 'saturday_period_1_stop' => '', 'sunday_period_1_start' => '', 'sunday_period_1_stop' => '', 'nightTemp' => '', 'workday_period_2_start' => '', 'workday_period_2_stop' => '', 'saturday_period_2_start' => '', 'saturday_period_2_stop' => '', 'sunday_period_2_start' => '', 'sunday_period_2_stop' => ''}</code>
| Ausblenden der Texte vor den DropDowns.
|-
| <code>
attr rg_thermostate nameStyle{($READING eq "Soll" ||$READING eq "Tag" ||$READING eq "%getConfig" ||$READING eq "Ist" ||$READING eq "Nacht" ||$READING eq "Ventil" )?'style="text-align:right"' :($READING eq "%burstXmit" )?'style="text-align:center"' :'style=""'}
</code>
| Ausrichten der Überschriften die keine readings sind.
|-
| <code>attr rg_thermostate nonames 1</code>
| Ausblenden der Device Namen.
|-
| <code>attr rg_thermostate valueColumns { 'Heizung' => 'colspan="2"', 'Temperatur' => 'colspan="4"', 'Status' => 'colspan="2"', 'Werktag' => 'colspan="2"', 'Samstag' => 'colspan="2"', 'Sonntag' => 'colspan="2"', 'alias' => 'colspan="2"'}</code>
| Diverse Readings sollen über mehrere Spalten dargestellt werden.
|-
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code>
| Formatierung für measured-temp und ValvePosition.
|-
| <code>attr rg_thermostate valueIcon { 'controlMode.auto' => 'sani_heating_automatic@green', 'controlMode.set_auto' => 'sani_heating_automatic@orange', 'controlMode.manual' => 'sani_heating_manual@red', 'controlMode.set_manual' => 'sani_heating_manual@orange', 'R-globalBtnLock.on' => 'secur_locked@green', 'R-globalBtnLock.on ' => 'secur_locked@green', 'R-globalBtnLock.set_on ' => 'secur_locked@orange', 'R-globalBtnLock.off' => 'secur_open@red', 'R-globalBtnLock.off ' => 'secur_open@red', 'R-globalBtnLock.set_off ' => 'secur_open@orange'}</code>
| Zuweisung der Icons.
|-
| <code>
attr rg_thermostate valueStyle{($READING eq "Heizung" ||$READING eq "Temperatur" ||$READING eq "Status" ||$READING eq "Wochenplan" ||$READING eq "Werktag" ||$READING eq "Samstag" ||$READING eq "Sonntag" )?'style="font-size:20px;;color:RoyalBlue;;text-align:center"' :($READING eq "alias" )?'style="font-size:11px;;font-weight:bold;;text-align:left"' :($READING eq "ValvePosition" &&$VALUE > 40 )?'style="font-weight:bold;;color:Orange;;text-align:left"' :($READING eq "desired-temp" ||$READING eq "measured-temp" )?'style="text-align:center"' :($READING eq "state" ||$READING eq "ValvePosition" )?'style="text-align:left"' :'style="text-align:right"'}
</code>
| Ausrichten und Einfärben der Readings.
|}
 
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===
 
Dieses Beispiel wurde für HM-TC-IT-WM-W-EU / HM-CC-RT-DN Geräte erstellt. Verwendung anderer Thermostate wird ggf. Anpassungen erforderlich machen. Die Geräte werden nicht automatisch ermittelt, sondern sind einzeln angegeben.
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben.
 
Die Gerätenamen (EG_WZ_WT01_Climate / EG_WZ_WT01, EG_WZ_TT01_Clima / EG_WZ_TT01 / EG_WZ_TT02, OG_BZ_WT01_Climate / OG_BZ_WT01, OG_BZ_TT01_Clima / OG_BZ_TT01, OG_SZ_WT01_Climate / OG_SZ_WT01, OG_SZ_TT01_Clima / OG_SZ_TT01, OG_DZ_WT01_Climate / OG_DZ_WT01, OG_DZ_TT01_Clima / OG_DZ_TT01) müssen natürlich entsprechend angepasst werden.
 
Hinweis: Bei den Geräten muss das Attribut „expert“ auf "1_on" gesetzt werden, andernfalls fehlt das Reading „R-globalBtnLock“. Dies hätte zur Folge, dass in der Spalte Lock der batteryLevel dargestellt wird.
 
{| class="wikitable"
! Definition !! Erläuterungen
|-
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]
|-
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br>
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br>
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br>
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02  \<br>
<>,<>,<>,<>,<>,<>,<>,<> \<br>
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01  \<br>
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01  \<br>
<>,<>,<>,<>,<>,<>,<>,<> \<br>
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01  \<br>
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br>
<>,<>,<>,<>,<>,<>,<>,<> \<br>
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01  \<br>
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code>
| ReadingsGoup anlegen.
|-
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br>
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br>
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code>
| Schrift fett setzen etc.
|-
| <code>attr heatingInfo commands {<br>
'heatingInfo.sollsetz'=>'desired-temp:5.0,12.0,18.0,19.0,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0',<br>
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br>
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br>
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code>
| Heizungssteuerung ermöglichen
|-
| <code>
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br>
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br>
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br>
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br>
EG_WZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler1",EG_WZ_TT02_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler2",'desired-temp' => ''}<br>
</code>
| Gewünschte Namen definieren.
|-
| <code>
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br>
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br>
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br>
else{$VALUE=0}}}
</code>
| Werte vorformatieren (für die Icon-Zuordnung).
|-
| <code>
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br>
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br>
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br>
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br>
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br>
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br>
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br>
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br>
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br>
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br>
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br>
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br>
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br>
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}
</code>
| Icons zuordnen.
|-
| <code>
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br>
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br>
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br>
else{'style="color:rgb(12,251,12);;"'}}}
</code>
| Farben (zu kalt: blau, zu warm: rot, ok: grün).
|-
| <code>
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br>
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br>
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br>
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}
</code>
</code>
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hiermit werden die Icons zum Ändern der gewünschten Temperatur dargestellt und im Bereich >=18 und <= 24 Grad anklickbar gemacht. Zwischen den Pfeilen wird der gerade eingestellte Wert angezeigt. Wenn dieser drei Sekunden nicht mehr geändert wurde wird die desired-temp auf diesen Wert gesetzt und die Anzeige zwischen den Pfeilen ausgeblendet.
| Messeinheiten und Zahlenwerte.
|}
|}


Zeile 424: Zeile 638:
! Definition !! Erläuterungen  
! Definition !! Erläuterungen  
|-
|-
| colspan=2 | [[Datei:rgHeizung4.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]
|-
|-
| style="width:40%" |<code>define myTemp readingsGroup <Raum>,<Tist>,<Tsoll>,<Mode>,<Tnight>,<Tday>,<Hum>,<BatTC>,<Vist>,<Vsoll>,<Verr>,<BatVD> Thermostat.(WZ|OZ|AZ|Bad|Kueche|SZ|GZ|Bad.OG):measured-temp,desired-temp,controlMode,night-temp,day-temp,humidity,battery,ValvePosition@{valveOfDevice($DEVICE)},ValveDesired@{valveOfDevice($DEVICE)},R-valveErrorPos@{valveOfDevice($DEVICE)},battery@{valveOfDevice($DEVICE)} Broetje:ToutIst </code>
| style="width:40%" |<code>define myTemp readingsGroup <Raum>,<Tist>,<Tsoll>,<Mode>,<Tnight>,<Tday>,<Hum>,<BatTC>,<Vist>,<Vsoll>,<Verr>,<BatVD> Thermostat.(WZ|OZ|AZ|Bad|Kueche|SZ|GZ|Bad.OG):measured-temp,desired-temp,controlMode,night-temp,day-temp,humidity,battery,ValvePosition@{valveOfDevice($DEVICE)},ValveDesired@{valveOfDevice($DEVICE)},R-valveErrorPos@{valveOfDevice($DEVICE)},battery@{valveOfDevice($DEVICE)} Broetje:ToutIst </code>
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilanriebs.  
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs.  
|-
|-
| <code>attr myTemp mapping    { 'Broetje' => 'Garten','Thermostat.AZ' => 'EG Arbeitszimmer','Thermostat.SZ' => 'OG Schlafzimmer','Thermostat.WZ'=>'EG Wohnzimmer','Thermostat.Kueche' => 'EG Küche','Thermostat.GZ' => 'OG Gästezimmer','Thermostat.Bad' => 'EG Bad','Thermostat.Bad.OG' => 'OG Bad','Thermostat.OZ' => 'EG Kaminzimmer','desired-temp' => <nowiki>''</nowiki> }</code>
| <code>attr myTemp mapping    { 'Broetje' => 'Garten','Thermostat.AZ' => 'EG Arbeitszimmer','Thermostat.SZ' => 'OG Schlafzimmer','Thermostat.WZ'=>'EG Wohnzimmer','Thermostat.Kueche' => 'EG Küche','Thermostat.GZ' => 'OG Gästezimmer','Thermostat.Bad' => 'EG Bad','Thermostat.Bad.OG' => 'OG Bad','Thermostat.OZ' => 'EG Kaminzimmer','desired-temp' => <nowiki>''</nowiki> }</code>
Zeile 445: Zeile 659:
| Die Formatierung der Werte.  
| Die Formatierung der Werte.  
|-
|-
| <code>
|<syntaxhighlight lang="perl">
#namen des ventil device aus thermostat device ableiten
#namen des ventil device aus thermostat device ableiten
sub valveOfDevice ($) {
sub valveOfDevice ($) {
  my ($DEVICE) = @_;
  my ($DEVICE) = @_;
    
    
  if ($DEVICE =~ m/AZ/) {
  if ($DEVICE =~ m/AZ/) {
  return "Ventil.".substr($DEVICE,11).".Nord";
return "Ventil.".substr($DEVICE,11).".Nord";
  } else {
  } else {
  return "Ventil.".substr($DEVICE,11); 
return "Ventil.".substr($DEVICE,11); 
  }
  }
}</code>
}</syntaxhighlight>
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hier wird aus dem Namen des Thermostaten der Name des zugehörigen Ventilantriebs abgeleitet.
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hier wird aus dem Namen des Thermostaten der Name des zugehörigen Ventilantriebs abgeleitet.
|}
|}
Da im {...} Teil des <reading>@<device> Arguments keine Leerzeichen oder Kommas vorkommen dürfen ist er in der Regel das Einfachste die Funktionalität wie in diesem Beispiel in eine eigene Routine auszulagern. Mit ein paar 'Tricks' lässt es sich aber manchmal auch ohne Leerzeichen oder Kommas lösen und dann direkt in die Definition schreiben:<code>...,ValvePosition@{$DEVICE=~s/Thermostat/Ventil/;$DEVICE;},...</code>
Da im {...} Teil des <reading>@<device> Arguments keine Leerzeichen oder Kommas vorkommen dürfen ist es in der Regel das Einfachste die Funktionalität wie in diesem Beispiel in eine eigene Routine auszulagern. Mit ein paar 'Tricks' lässt es sich aber manchmal auch ohne Leerzeichen oder Kommas lösen und dann direkt in die Definition schreiben:<code>...,ValvePosition@{$DEVICE=~s/Thermostat/Ventil/;$DEVICE;},...</code>
 
=== Inhalte filtern ===
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:
 
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code>
 
In diesem Bsp. werden alle Zeilen/Devices, deren Value > 0 sind, angezeigt. Alle anderen werden als <code>undef</code> formatiert und erscheinen damit nicht im Listing.
 
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).
 
=== Inhalte berechnen ===
Will man nur kleine Berechnungen machen und möchte diese aus irgendeinem Grund nicht in die [[99_myUtils_anlegen|99_myUtils.pm]] auslagern (z.B. der Übersicht halber), so kann man die Berechnung auch direkt in <code>valueFormat</code> einbauen. Ein ganz einfaches Bsp. dazu ist das Filtern von Inhalten ([[ReadingsGroup#Inhalte filtern|s.o.]]).
 
Im konkreten Beispiel ist via CalDAV ein Abfallkalender eingebunden, der die folgenden Einträge erzeugt:
 
<syntaxhighlight lang="text">
t_001_bdate 06.02.2017 2017-02-04 14:40:49
t_001_btime 00:00:00  2017-02-04 14:40:49
...
t_001_summary Gelber Sack 2017-02-04 14:40:49
</syntaxhighlight>
 
Daraus lässt sich mit <code>readingsGroup</code> so direkt keine ordentliche Darstellung erzeugen. Gewünscht ist aber das folgende Format eines Zeileneintrags:
 
<code>06.02.2017 Gelber Sack</code>
 
Dies lässt sich durch eine noch einigermaßen kurze Berechnung erzeugen - längere Berechnungen sollte man definitiv in myUtils auslagern (vgl. [[ReadingsGroup#Enigma Receiver|hier]]). Der folgende Code filtert zusätzlich weitere nicht erwünschte Einträge aus und macht noch eine Wortanpassung:
 
<syntaxhighlight lang="perl">
# die readingsGroup reagiert nur auf summary-Einträge ( .* steht für eine beliebige Anzahl beliebiger Zeichen)
 
define Abfallkalender readingsGroup calvAbfallKalender:t_.*summary
 
attr Abfallkalender valueFormat {
  use Time::Local;;
  # alle Einträge Bio... und 4-wöchige Rest... ignorieren
  if (not $VALUE =~ /Bio/ and
      not $VALUE =~ /Restmülltonne..4/) {
# readingname für bdate zum summary erzeugen
my $rBdate = $READING =~ s/summary/bdate/r;;
# readingvalue für bdate auslesen
my $vDate = ReadingsVal($DEVICE,$rBdate,"");;
# wenn value 'tonne' enthält dieses entfernen
if ($VALUE =~ /tonne/) {
    $vDate . " " . substr($VALUE,0,index($VALUE,'tonne'));;
} else {
    "$vDate %VALUE";;
}
  } else {
    undef;;
  }
}
</syntaxhighlight>
Der Code in der cfg-Datei würde bei valueFormat zwischen den Hauptklammern immer ;;;; statt ;; und an jedem Zeilenende ein \ haben.


=== Dynamische Inhalte ===
=== Dynamische Inhalte ===
Zeile 479: Zeile 747:
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}
</pre>
</pre>


=== Enable/Disable Button am Beispiel eines WeekdayTimer ===
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===
Dieses Beispiel zeigt die Anwendung einer readingsGroup, um im Frontend einen Enable/Disable Button für ein Objekt darzustellen. Für den WeekdayTimer gibt es hier spezielle Erweiterungen (set Routinen, um das disable Attribut zu setzen, Reading "disabled"). Es gibt aber auch eine allgemeinere Variante (siehe [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut "disable" unterstützen.
Dieses Beispiel zeigt die Anwendung einer readingsGroup, um im Frontend einen Enable/Disable Button für ein Objekt darzustellen. Für den [[WeekdayTimer]] gibt es hier spezielle Erweiterungen (set Routinen, um das Attribut ''disable'' zu setzen). Es gibt aber auch eine allgemeinere Variante (siehe {{Link2Forum|Topic=23655|Message=169141|LinkText=diesen Forumsbeitrag}}) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.
{| class="wikitable"
{| class="wikitable"
! Definition !! Erläuterungen  
! Definition !! Erläuterungen  
Zeile 489: Zeile 756:
|-
|-
| style="width:40%" |<code>define rg_Timer_Wasser readingsGroup timer_Wasser_..:disabled,+DEF,<{rg_timer_Wasser_show_conditional($DEVICE,"nextUpdate")}@disabled>,<{rg_timer_Wasser_show_conditional($DEVICE,"nextValue")}@disabled></code>
| style="width:40%" |<code>define rg_Timer_Wasser readingsGroup timer_Wasser_..:disabled,+DEF,<{rg_timer_Wasser_show_conditional($DEVICE,"nextUpdate")}@disabled>,<{rg_timer_Wasser_show_conditional($DEVICE,"nextValue")}@disabled></code>
| Definition der angezeigten Readings. Das Reading disabled wird mit den u.a. Attributen zum Button, +DEF zeigt die Definition, d.h. die Schaltzeiten, des Timers an. Die Readings nextUpdate und nextValue sollen nur angezeigt werden, falls der Timer aktiv ist. Hierfür sorgt eine Routine <code>rg_timer_Wasser_show_conditional</code>, welche in der 99_myUtils.pm definiert wird. Das abschließende @disabled sorgt dafür, daß der LongPoll Mechanismus die Anzeige sofort ändert, wenn der Button betätigt wird.  
| Definition der angezeigten Readings. Das Attribut ''disabled'' wird mit weiteren Einstellungen (''commands'') zum Button, +DEF zeigt die Definition, d.h. die Schaltzeiten, des Timers an. Die Readings nextUpdate und nextValue sollen nur angezeigt werden, falls der Timer aktiv ist. Hierfür sorgt eine Routine <code>rg_timer_Wasser_show_conditional</code>, die in der 99_myUtils.pm definiert wird. Das abschließende @disabled sorgt dafür, dass der LongPoll Mechanismus die Anzeige sofort ändert, wenn der Button betätigt wird.  
|-
|-
| <code>attr rg_Timer_Wasser valueFormat  { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code>
| <code>attr rg_Timer_Wasser valueFormat  { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code>
| Der Name des Timers wird aus dem interal Reading "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt.  
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt.  
|-
|-
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code>
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code>
Zeile 498: Zeile 765:
|-
|-
| <code>attr rg_Timer_Wasser commands  { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code>
| <code>attr rg_Timer_Wasser commands  { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code>
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, daß der Timer deaktiviert wird ("set $DEVICE disable").
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") ist, sorgt ein Klick auf den Button dafür, dass der Timer deaktiviert wird ("set $DEVICE disable").
|-
|-
|<code>
|<syntaxhighlight lang="perl">
sub rg_timer_Wasser_show_conditional($$)
sub rg_timer_Wasser_show_conditional($$)
{
{
  my ($DEVICE,$READING) = @_;
  my ($DEVICE,$READING) = @_;
  return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )?  
  return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )?  
      ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";
    ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";
}</code>
}</syntaxhighlight>
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hiermit wird das übergebene Reading des Timers nur angezeigt, wenn der Timer aktiv ist. Andernfalls wird der String "disabled" stattdessen angezeigt.
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]: Hiermit wird das übergebene Reading des Timers nur angezeigt, wenn der Timer aktiv ist. Andernfalls wird der String "disabled" angezeigt.
|}
|}
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}
Inzwischen ist es auch möglich das commands Mapping auf Attribute anzuwenden. Die Syntax ist die gleiche wie für die set Kommandos. Um das Beispiel übersichtlich zu halten werden hier die Werte und Icons auch für deaktivierte WeekdayTimer angezeigt.
{| class="wikitable"
! Definition !! Erläuterungen
|-
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]
|-
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code>
| Definition der angezeigten Readings. Das Attribut ''disable'' wird mit weiteren Einstellungen (''commands'') zum Button. Durch das ! wird das Attribut auch dann angezeigt wenn es noch nicht gesetzt ist. 
|-
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code>
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.
|-
| <code>attr rgTimer valueFormat  '{(split(" ", $VALUE))[1]}'</code>
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt.
|-
| <code>attr rgTimer commands  { disable => 'disable:' }</code>
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.
|}
=== Readings löschen ===
Es kann vorkommen, dass Readings angezeigt werden, die gar nicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbenannt hat, kann auch der alte Readingsname immer noch angezeigt werden. Solche Readings können mit der globalen Funktion {{Link2CmdRef|Anker=deletereading|Label=deletereading}} gelöscht werden.
'''Achtung:''' Auf jeden Fall die {{Link2CmdRef|Anker=deletereading}} dazu lesen!
Beispiel:
Im HTTPMOD des [[Pollenflug]] war zuerst das <code>reading04Name Graeser</code> definiert und wurde später in <code>reading04Name Gräser</code> umbenannt. In der zugehörigen ReadingGroup wurden dann konsequent beide Varianten dargestellt - auch nachdem alle Alt-Einträge aus den Logs entfernt wurden. Erst ein <code>deletereading Pollenflug Graeser</code> in der FHEM-Befehlszeile hat das veraltete Reading entfernt.
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, z.B. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt.
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (z.B. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag {{Link2Forum|Topic=37194|Message=440446}} :
<pre>
define Pollenflugvorhersage allergy <PLZ>
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red
attr Pollenflugvorhersage stateFormat fc1_maximum
attr Pollenflugvorhersage updateEmpty 1
attr Pollenflugvorhersage updateIgnored 1
# Pollen in Spalten, Tage in Zeilen
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \
Pollenflugvorhersage:fc1_day_of_week,fc1_Ampfer,fc1_Ambrosia,fc1_Beifuß,fc1_Birke,fc1_Buche,fc1_Eiche,fc1_Erle,fc1_Gräser,fc1_Hasel,fc1_Pappel,fc1_Roggen,fc1_Ulme,fc1_Wegerich,fc1_Weide \
Pollenflugvorhersage:fc2_day_of_week,fc2_Ampfer,fc2_Ambrosia,fc2_Beifuß,fc2_Birke,fc2_Buche,fc2_Eiche,fc2_Erle,fc2_Gräser,fc2_Hasel,fc2_Pappel,fc2_Roggen,fc2_Ulme,fc2_Wegerich,fc2_Weide \
Pollenflugvorhersage:fc3_day_of_week,fc3_Ampfer,fc3_Ambrosia,fc3_Beifuß,fc3_Birke,fc3_Buche,fc3_Eiche,fc3_Erle,fc3_Gräser,fc3_Hasel,fc3_Pappel,fc3_Roggen,fc3_Ulme,fc3_Wegerich,fc3_Weide \
Pollenflugvorhersage:fc4_day_of_week,fc4_Ampfer,fc4_Ambrosia,fc4_Beifuß,fc4_Birke,fc4_Buche,fc4_Eiche,fc4_Erle,fc4_Gräser,fc4_Hasel,fc4_Pappel,fc4_Roggen,fc4_Ulme,fc4_Wegerich,fc4_Weide \
Pollenflugvorhersage:fc5_day_of_week,fc5_Ampfer,fc5_Ambrosia,fc5_Beifuß,fc5_Birke,fc5_Buche,fc5_Eiche,fc5_Erle,fc5_Gräser,fc5_Hasel,fc5_Pappel,fc5_Roggen,fc5_Ulme,fc5_Wegerich,fc5_Weide \
Pollenflugvorhersage:fc6_day_of_week,fc6_Ampfer,fc6_Ambrosia,fc6_Beifuß,fc6_Birke,fc6_Buche,fc6_Eiche,fc6_Erle,fc6_Gräser,fc6_Hasel,fc6_Pappel,fc6_Roggen,fc6_Ulme,fc6_Wegerich,fc6_Weide \
Pollenflugvorhersage:fc7_day_of_week,fc7_Ampfer,fc7_Ambrosia,fc7_Beifuß,fc7_Birke,fc7_Buche,fc7_Eiche,fc7_Erle,fc7_Gräser,fc7_Hasel,fc7_Pappel,fc7_Roggen,fc7_Ulme,fc7_Wegerich,fc7_Weide
attr PollenAlarm nonames 1
attr PollenAlarm valueFormat %VALUE
attr PollenAlarm valueIcon %VALUE
# Tage in Spalten, Pollen in Zeilen
define PollenAlarmVertikal readingsGroup Pollenflugvorhersage:<Pollen>,fc0_day_of_week,fc1_day_of_week,fc2_day_of_week,fc3_day_of_week,fc4_day_of_week,fc5_day_of_week,fc6_day_of_week,fc7_day_of_week \
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide
</pre>
== Berechnungen ==
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}
Das Rechnen funktioniert über das Flag "$", mit dem eine Funktion angegeben werden kann, die auf beliebige Kombinationen von Zeilen, Spalten und einzelnen Zellen angewendet wird. Ähnlich wie in einer Tabellenkalkulation.
Ein Beispiel:
:<code>define rg readingsGroup .*:temperature rg:$avg</code>
Damit wird eine readingsGroup über alle ''temperature'' Readings definiert. In einer zusätzlichen Zeile am Ende wird mit ''$avg'' der Durchschnittswert aller darüber liegenden Temperaturen angezeigt.
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit
*<code><operator></code>: sum, avg, min, max, scalar, count oder der Name einer beliebigen anderen Funktion, die ein Array mit allen Werten übergeben bekommt und ein Ergebnis zurückliefert.
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren.
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können
** einzelne Werte,
** durch Komma getrennte Aufzählungen,
** mit .. angegebene Wertebereiche
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle
:verwendet werden.
Alle Möglichkeiten sind kombinierbar. Die Zählung der Zeilen und Spalten beginnt bei 1. Eine nicht vorhandene Zeilenangabe wird durch den Bereich von Zeile 1 bis zur aktuellen Zeile ersetzt, eine nicht vorhandene Spalte durch die aktuelle Spalte.
Es ergeben sich somit unter anderem folgende Möglichkeiten:
*<code>$sum</code> equivalent zu <code>$sum(1..$ROW), $sum(:$COLUMN)</code> und <code>$sum(1..$ROW:$COLUMN)</code> die Summe der Werte in der Spalte über der aktuellen Zelle.
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.
Die Ergebnisse werden im Weiteren wie normale Readings behandelt. Sie lassen sich von links oben nach rechts unten kaskadieren und lassen sich über valuePrefix, valueSuffix, valueFormat und valueStyle in der Darstellung beeinflussen. Also z.B. einfärben, als Balkendiagramm darstellen, ...
Mit Hilfe der Funktionalität zum auf- und zu-klappen von Teilen einer readingsGroup lassen sich z.B. im zusammengeklappten Zustand Summen, Extremwerte oder andere Ausreißer anzeigen und die Details nur beim Aufklappen zeigen.
Weitere Möglichkeiten:
* Attribut <code>firstCalcRow</code>: Hiermit kann der Default für die Nummer der ersten Zeile vorgegeben werden (sofern im Ausdruck nichts genaueres angegeben ist). firstCalcRow sollte z.B. auf 2 gesetzt werden, wenn in der readingsGroup Spaltenüberschriften verwendet werden.
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebnis ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.
* das <code>alwaysTrigger</code> Attribut kann jetzt auch den Wert 2 bekommen. Damit werden in der readingsGroup Readings für alle durch die Aggregation gebildeten Werte und entsprechende Events auch dann erzeugt wenn die readingsGroup nicht angezeigt wird. Wenn ein Alias-Name vergeben ist, wird dieser auch für den Reading-Namen verwendet.
* Über den operator <code>$count(<wert>)(<zellen>)</code> um das Vorkommen von <code><wert></code> in den angegebenen Zellen zu zählen. <code><wert></code> kann enweder direkt der zu zählende Wert sein (ohne Anführungzeichen) oder eine in / eingeschlossene regex. Mit <code>!<wert></code> kann das Nicht-Vorkommen von <code><wert></code> gezählt werden.
=== Ein interaktives Beispiel ===
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]
In drei [[dummy]] Objekten lässt sich jeweils ein Reading über einen Slider einstellen. In der darunter liegenden readingsGroup werden diese Readings und diverse daraus abgeleitete Werte dargestellt. Alle Readings und die daraus abgeleiteten Werte werden live per longpoll aktualisiert, wenn die slider bewegt werden.
<br clear=all>
<pre>
  define t1 dummy
  attr t1 room rg
  attr t1 setList state:slider,-10,1,30
  attr t1 webCmd state
  define t2 dummy
  attr t2 room rg
  attr t2 setList state:slider,-10,1,30
  attr t2 webCmd state
  define t3 dummy
  attr t3 room rg
  attr t3 setList state:slider,-10,1,30
  attr t3 webCmd state
  define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\
  t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\
  <hr>\
  rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\
  <hr>\
  t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\
  attr rg nonames 1
  attr rg room rg
  attr rg style style='text-align:center'
  attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }
  attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }
  attr rg valueSuffix { state => '&deg;;C' }
</pre>


== Links und Trigger ==
== Links und Trigger ==
=== readingsGroup mit Link ===
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten  
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten  
Zeile 517: Zeile 931:
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code>
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code>


<pre>use vars qw($FW_ME);
<syntaxhighlight lang="perl">
use vars qw($FW_ME);
use vars qw($FW_subdir);
use vars qw($FW_subdir);
sub
sub
Zeile 531: Zeile 946:


   return ($ret,0);
   return ($ret,0);
}</pre>
}</syntaxhighlight>
 
Wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:
:<code>{myUtils_refresh("WEB")}</code>
mit folgendem code in 99_myUtils.pm:
<syntaxhighlight lang="perl">
sub                                                                                   
myUtils_refresh($)                                                                     
{                                                                                     
  my ($name) = @_;                                                                     
                                                                                       
  FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );
}</syntaxhighlight>
 
 
Ein weiteres Beispiel für 'custom links und trigger' findet sich in {{Link2Forum|Topic=14425|Message=109383|LinkText=diesem Forenbeitrag}}: dort wird damit eine readingsGroup dynamisch umgeschaltet, um nur die eingeschalteten, nur die ausgeschalteten oder alle Lampen anzuzeigen.
 
=== sub rg ===
Damit beim Klicken auf ein Icon oder einen Text in einer readingsGroup etwas passiert ist es möglich dies über das commands Attribut auf ein <code>'trigger ntfy_rg $DEVICE $READING'</code> oder Ähnliches zu mappen.
Anlegen des ntfy_rg notify
<pre>
define ntfy_rg notify ntfy_rg {rg($EVENT)}
</pre>
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]
<syntaxhighlight lang="perl">
sub rg($){
  my @input    = split(/[§\s]+/,shift);
  my $device  = $input[0];
  my $function = $input[1];
 
if($function eq "clima"){
  my $room =  AttrVal($device, 'room', 'undef');
  $room =~ s/\D//g;
 
  return(("d_climaControl_".$room));
}
elsif($function eq "device"){
  return InternalVal($device,"device","device error");
}
elsif($function eq "controlMode"){
  my $controlMode = ReadingsVal($device,"controlMode","controlMode error");
 
  if($controlMode ~~ /manual/)
    {fhem("set $device controlMode auto")}
  elsif($controlMode ~~ /auto/)
    {fhem("set $device controlMode manual")};
}
elsif($function eq "globalBtnLock"){
  my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");
 
  if($globalBtnLock ~~ /off/){
    {fhem("set $device regSet globalBtnLock on")}
    {fhem ("set $device getConfig")}
  }
  elsif($globalBtnLock ~~ /on/){
    {fhem("set $device regSet globalBtnLock off")}
    {fhem ("set $device getConfig")}
  };
}
elsif($function eq "state"){
  my $state = Value($device);
 
  if($state ~~ /off/){
    {fhem("set $device on")}
  }
  elsif($state ~~ /on/){
    {fhem("set $device off")}
  };
}
elsif($function eq "setTimeTable"){
  my $room        =  AttrVal($device, 'room', 'undef');
  $room        =~ s/\D//g;
  my $climaControl = ("d_climaControl_".$room);
  my $dayTemp          = ReadingsVal( $climaControl, "dayTemp"          , 21.0    );
  my $nightTemp        = ReadingsVal( $climaControl, "nightTemp"        , 17.0    );
  my $workday_period_1_start  = ReadingsVal( $climaControl, "workday_period_1_start"  , "06:30" );
  my $workday_period_1_stop  = ReadingsVal( $climaControl, "workday_period_1_stop"  , "18:00" );
  my $workday_period_2_start  = ReadingsVal( $climaControl, "workday_period_2_start"  , "24:00" );
  my $workday_period_2_stop  = ReadingsVal( $climaControl, "workday_period_2_stop"  , "24:00" );
  my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );
  my $saturday_period_1_stop  = ReadingsVal( $climaControl, "saturday_period_1_stop"  , "12:00" );
  my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );
  my $saturday_period_2_stop  = ReadingsVal( $climaControl, "saturday_period_2_stop"  , "24:00" );
  my $sunday_period_1_start  = ReadingsVal( $climaControl, "sunday_period_1_start"  , "24:00" );
  my $sunday_period_1_stop    = ReadingsVal( $climaControl, "sunday_period_1_stop"    , "24:00" );
  my $sunday_period_2_start  = ReadingsVal( $climaControl, "sunday_period_2_start"  , "24:00" );
  my $sunday_period_2_stop    = ReadingsVal( $climaControl, "sunday_period_2_stop"    , "24:00" );


Ein weiteres Beispiel für 'custom links und trigger' findet sich im [http://forum.fhem.de/index.php/topic,14425.msg109383.html#msg109383 Forum]: dort wird damit eine readingsGroup dynamisch umgeschaltet, um nur die eingeschalteten, nur die ausgeschalteten oder alle Lampen anzuzeigen.
  {fhem("set $device tempListMon prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListTue prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListWed prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListThu prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListFri prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListSat prep $saturday_period_1_start $nightTemp $saturday_period_1_stop $dayTemp $saturday_period_2_start $nightTemp $saturday_period_2_stop $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListSun exec $sunday_period_1_start  $nightTemp $sunday_period_1_stop  $dayTemp $sunday_period_2_start  $nightTemp $sunday_period_2_stop  $dayTemp 24:00 $nightTemp")};
}
}
</syntaxhighlight>
Hier sind die benötigten CodeBlöcke für [[ReadingsGroup#Heizungswerte.2C_Status.2C_Steuerung_und_Wochenprofil|Heizungswerte, Status, Steuerung und Wochenprofil]] enthalten, aber auch um state zu triggern.


== Sonstiges ==
== Sonstiges ==
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.


===Lesbar machen===
=== Lesbar machen ===
Für die meisten Attribute gilt:
Für die meisten Attribute gilt:


*Wenn es komplexer wird ist es einfacher den Code in eine sub in 99_myUtils auszulagern und diese aufzurufen:
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:
<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code>
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code>
 
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:
*code für unterschiedliche readings kann man auch im mapping schon aufteilen:
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code>
<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code>
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:
 
  if( $READING eq ... ) {
*Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:
  <code>if( $READING eq ... ) {
   return xxx if( $VALUE < 1 );
   return xxx if( $VALUE < 1 );
   return yyy if( $VALUE < 1.5 );
   return yyy if( $VALUE < 1.5 );
Zeile 554: Zeile 1.063:
  } elsif( $READING eq ... ) {
  } elsif( $READING eq ... ) {
   ...
   ...
  }</code>
  }


Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.


===group===
=== readingsGroup in einer Gruppe ===
Wenn der doppelte Rahmen um eine readingsGroup in eine group  stört, lässt er sich mit dem passenden style entfernen:  
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen:  
<code>attr <device> style style="border:0px;background:none;box-shadow:none"</code>  
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code>
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.
 
Anwendungs-Bsp: [[Pollenflug]]
 
=== Einfache Balkendiagramme ===
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:
:<code>attr <rgName> valueStyle style="width:200px; text-align:center; border: 1px solid #ccc; background:-webkit-linear-gradient(left, red $VALUE%, rgba(0,0,0,0) $VALUE%)"</code>
 
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.
 
Diese direkte Definition des <code>valueStyle</code> ist allerdings sehr unflexibel - bspw. müsste der <code>$VALUE</code> zufällig max 100 erreichen und es darf nur ein Browsertyp eingesetzt werden, damit alles sauber funktioniert.
 
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:
 
<syntaxhighlight lang="perl">
sub Balkenanzeige($)
{
    # Zuweisung der übergebenen Variablen
    my ($val) = @_;
 
    # Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)
    my $maxValue = 3;
 
    # Normalisierung auf 100%-Wert
    my $percent = $val / $maxValue * 100;
 
    # Definition des valueStyles
    my $stylestring = 'style="'.
        'width: 200px; '.
'text-align:center; '.
'border: 1px solid #ccc ;'.
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.
'background-image:    -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.
'background-image:    -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.
'background-image:      -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.
'background-image:        linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';
 
    # Rückgabe des definierten Strings
    return $stylestring;
}
</syntaxhighlight>
 
Der Aufruf sähe dann wie folgt aus:
 
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code>
 
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:
* width      - Breite des Balkenrahmens
* text-align - Ausrichtung des Texts
* border    - Format des Balkenrahmens
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''
*** left            - linksbündiger Balken
*** red x%          - roter Balken x% breit
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%
 
''(*) linear-gradient wird in verschiedenen Browsern unterschiedlich umgesetzt. Deshalb sollten immer alle Varianten zusammen angegeben werden, damit die Darstellung auf allen Browsern funktioniert. (vgl. Link unten)''
 
Weitere Infos zu:
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}
* [[99_myUtils_anlegen|99_myUtils.pm]]
 
Anwendungs-Bsp: [[Pollenflug]]
 
=== readingsGroup Styling mit CSS ===
Jede readingsGroup lässt sich durch CSS individuell stylen.
 
==== Allgemeines ====
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwendig eine eigene .css Datei (z.B. ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf z.B. ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.
 
==== Erweiterte Device Übersicht ====
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zur Detail-Seite der ReadingsGroup und Links zu der jeweiligen Device-Detail-Seite, dargestellt.
 
{| class="wikitable"
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]
|}
 
===== Definition =====
<pre>
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\
attr rg_devices noheading 1
attr rg_devices nonames 1
attr rg_devices notime 1
attr rg_devices room ReadingsGroup Styling
attr rg_devices style class="block wide rgDevices"
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh"  }
attr rg_devices valueIcon { state => '%devStateIcon' }
</pre>
 
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötig
das Attribut ''style'' anzupassen.
{| class="wikitable"
! Definition !! Erläuterungen
|-
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code>
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.
|}
===== Funktion rgLink() =====
Die Funktion rgLink($name,$action,$label) liefert einen Link mit dem Namen $label zurück. Der Code gehört in die [[99 myUtils anlegen|99_myUtils.pm]].
* $name - Name des Device das aufgerufen werden soll
* $action - Aktion die Ausgeführt werden soll.
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einen zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist
** ''detail'' erzeugt einen Link zu Device-Detail Seite
* $label - Link-Name
<syntaxhighlight lang="perl">
sub rgLink($$$){
  my ($name,$action,$label) = @_;
  my $link = "";
  my $fhemLink = "";
  my $txt = "";
  my $ret = "";
  my $divStyle = "";
  my $aStyle = "";
 
  # FHEM Variablen einbinden
  use vars qw($FW_ME);
  use vars qw($FW_subdir);
  use vars qw($FW_ss);
  use vars qw($FW_tp);
 
  if( $action eq "konfigurieren" ){
    $fhemLink  = "detail=$name";
    $divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";
  }
  elsif( $action eq "detail" ){
    $fhemLink  = "detail=$name";
    $divStyle = "cursor:pointer;display:inline;";
  }
 
  $link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';
  $txt  = '<div style="' . $divStyle . '">' . $link . '</div>';
  $ret  = "$txt";
 
  return $ret;
}
</syntaxhighlight>
 
{{Randnotiz|RNText=Tipp
Verwende zum Bearbeiten der eigenen .css Dateien entweder den [[Konfiguration#Syntaxhervorhebung|Codemirror Editor]] oder einen eigenen Editor mit [http://de.wikipedia.org/wiki/Syntaxhervorhebung Syntax Highlighting] . Das hilft bei der Fehlersuche enorm. }}
 
===== Styling =====
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenem Editor bearbeitet werden.
 
ios7ReadingsGroups.css:
<pre>
/*  Readings Groups Devices */
table.rgDevices tr td{ text-align: center; }
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }
table.rgDevices tr td:first-child{  /* 1. Spalte */ width: 45px; text-align: center; }
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%;  text-align: left; }
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }
</pre>
 
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt.
 
{| class="wikitable"
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]
|}
 
===== Allgemeines =====
Mit CSS ist man in der Lage auf die aktuelle Bildschirmlage zu reagieren. Alle Anweisungen die in diesen beiden Funktionen zwischen den beiden { } stehen, werden je nach Bildschirmlage aufgerufen
<pre>
/* Portrait Modus */
@media all and (orientation:portrait) { }
 
/* Landscape Modus */
@media all and (orientation:landscape) { }
</pre>
 
===== Styling =====
{{Randnotiz|RNText=Info
* ''width: xx%'' ändert die Breite der Spalte
* ''display: none'' blendet die Spalte aus}}
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css
 
ios7smallscreenReadingsGroups.css
<pre>
/* landscape und portrait modus */
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }
 
/* Portrait Modus */
@media all and (orientation:portrait) {
  table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }
  table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }
  table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }
  table.rgDevices tr td:nth-child(6){ width: 0; display: none; }
  table.rgDevices tr td div a svg{ margin-left: 90px; }
}
 
/* Landscape Modus */
@media all and (orientation:landscape) {
  table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }
  table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }
}
</pre>
 
==== Plots im Portrait Modus des Smartphones ausblenden ====
{| class="wikitable"
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]
|}
 
Um den Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:
<pre>
@media all and (orientation:portrait) {
  .SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }
}
</pre>


[[Kategorie:HOWTOS]]
[[Kategorie:HOWTOS]]
[[Kategorie:Code Snippets]]
[[Kategorie:Code Snippets]]

Aktuelle Version vom 3. Oktober 2019, 22:32 Uhr


readingsGroup
Zweck / Funktion
Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung
Allgemein
Typ Hilfsmodul
Details
Dokumentation EN / DE
Support (Forum) Frontends
Modulname 33_readingsGroup.pm
Ersteller Andre (Forum / Wiki)
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


Das FHEM-Hilfsmodul readingsGroup bietet eine einfache Möglichkeit, Readings (kein Präfix vor dem Reading-Namen), Internals (Präfix "+" vor dem Namen des internen Wertes) und Attributes (Präfix "?" vor dem Namen des Attributs) von einem oder mehreren Devices darzustellen und flexibel zu formatieren.

Die Aktualisierung im Browserfenster geschieht per longpoll und überträgt nur die jeweils geänderten Zellen. Wenn eine readingsGroup in keinem Browserfenster angezeigt wird, findet keine longpoll Aktualisierung statt.

Definition

Siehe commandref/readingsGroup.

Attribute

Info green.pngIn allen Mappings die einen Hash verwenden muss der Key (das was jeweils links von => Operator steht) in Anführungszeichen stehen. Die einzige Ausnahme hiervon sind Keys die aus einem String bestehen der mit einem Buchstaben beginnt und nur Buchstaben und Zahlen enthält.

Weitergehende Erläuterungen zu einzelnen Attributen.

Die komplette Liste der Attribute ist der commandref zu entnehmen.

noheading

ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel

Das Attribut noheading führt dazu, dass der Alias der ReadingsGroup nicht mehr als Titel angezeigt wird. Das kann wünschenswert sein, wenn die ReadingsGroup auf einer Dashboard-Seite angezeigt werden soll, hat allerdings den Nachteil, dass die Detail-Ansicht der ReadingsGroup nicht mehr über einen Klick auf den Titel aufgerufen werden kann. Der Einstellungsdialog der ReadingsGroup ist dann nur noch (z. B.) über

  • list TYPE=readingsGroup
  • einen "Probably associated with"-Link eines anderen Objekts oder über
  • manuelle Modifikation der URL eines anderen Objekts (http:.../fhem?detail=<objektname>)

erreichbar.

nolinks

Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.

nostate

Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.

notime

Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.

mapping

mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um

Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.

valueFormat

valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (z.B. ReadingsGroup#Ausgabestil (hier rechtsbündig)). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um

Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.

valueIcon

valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (z.B. einfach, etwas mehr).

Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.

valueStyle

valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (z.B. einfach, erweitert, komplex).

Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.

Beispiele

Bitte beachten: die folgenden Beispiele enthalten keine Maskierungen oder Verdoppelungen für ; und Zeilenende, sondern sind so angegeben, wie sie im Web Interface im Befehls-Eingabefeld, nach Klick auf DEF und im Attribut-Eingabefeld eingegeben werden. Beim manuellen Einfügen in eine Konfigurationsdatei sind diese Maskierungen oder Verdoppelungen natürlich vorzunehmen.

Einfache Auswahl über Reading-Namen

Definition Erläuterungen Aussehen
define battStatus readingsGroup .*:[Bb]attery Alle readings mit Namen Battery oder battery von allen Devices.
RgBattery.png
attr battStatus alias FHT Batteriestatus Der Alias wird als Zeilentitel verwendet
attr battStatus mapping %ROOM Mapping %ROOM führt dazu, dass der Raumname als Zeilentitel angezeigt wird.

Übersicht HomeMatic Geräte

define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr

Auswahl über Reading-Namen, Status als Symbol dargestellt

Definition Erläuterungen Aussehen
define rg_battery readingsGroup .*:battery Alle readings mit Namen battery von allen Devices.
RgBattery2.png
attr rg_battery alias Batteriestatus Der Alias wird als Überschrift verwendet
attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'} Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.
attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" } Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.

Reading-Werte zuordnen (Icon / Text)

Definition Erläuterungen Aussehen
define rg readingsGroup Contact.Dachboden_gross:sensed.* Alle sensedreadings des Contact.Dachboden_gross device.
RgFenster.png
attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' } Die Zuordnung rechts/links
attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"} Die Zuordnung von reading Wert zu Icon Namen.
attr rg_battery valueIcon %VALUE Statt des reading Werts soll ein Icon angezeigt werden.

Formatvorgabe für Ausgabewerte

Definition Erläuterungen Aussehen
define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint Alle readings mit Namen temperature, humidity, dewpoint von allen Devices des Typs CUL_WS
S300TH-Werte in einer readingsGroup
attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt Der Alias der readingsGroup wird als Überschrift verwendet
attr TempHygro mapping %ALIAS Mapping %ALIAS führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.
attr TempHygro valueFormat { temperature => "%.1f&deg;C", humidity => "%.1f %%", dewpoint => "%.1f&deg;C"} Formatierung der Ausgabewerte. Achtung: "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!

Ausgabestil (hier rechtsbündig)

Definition Erläuterungen Aussehen
define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure

Die readings mit Namen temperature, humidity und pressure vom Device WetterXXX jeweils mit einem Icon und einem Label davor.
RgWetter.png
attr Wetter valueFormat { temperature => '%1.f &deg;C', humidity => '%1.f %%', pressure => '%i mbar' } Die Formatierung der Readingswerte
attr Wetter valueStyle style="text-align:right" Die Readings sollen rechtsbündig dargestellt werden.

Internal Value ausgeben

Dieses Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).

Definition Erläuterungen Aussehen
define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI Den RSSI Wert aller Devices (am IODev cul) die einen solchen haben anzeigen.
Achtung: "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.
RgculRSSI.png

Internal Values ausgeben

Definition Erläuterungen Aussehen
define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME Den RSSI Wert mit der zugehörigen Zeit aller Devices (am IODev cul) die einen solchen haben anzeigen.
Achtung: "internal values" werden nicht per longpoll aktualisiert, sondern nur beim Seitenaufbau.
"Internal Values" werden durch das vorangestellte + (Pluszeichen) identifiziert.
RgculRSSI2.png
attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef} Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).

Alle Readings eines Gerätes, mit Ausnahme von...

Definition Erläuterungen Aussehen
define Systemstatus readingsGroup sysstat Alle readings des sysstat Device
RgSysstat.png
attr Systemstatus nostate 1 Ohne state
attr Systemstatus notime 1 Ohne readings timestamp
attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &deg;C'} Die Zuordnung der reading Namen zu den Zeilentiteln

Anzeige auf einem Floorplan

Definition Erläuterungen Aussehen
define Heizung readingsGroup t(1|2|3):temperature Die Temperatur readings der Devices t1, t2 und t3
RgHeizung.png
attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&ücklauf', 't3.temperature' => 'Zirkulation'} Die Zuordnung der reading Namen zu den Zeilentiteln
attr Heizung nameStyle style="text-align:left" Zeilentitel linksbündig wegen floorplan
attr Heizung style style="font-size:20px;color:lightgray" Großer Font und Farbe passend für den floorplan
attr Heizung notime 1 Ohne readings timestamp
attr Heizung valueFormat : %.1f &deg;C Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit


LightScene DropDown-Menü für smallscreen Styles oder Floorplan

Definition Erläuterungen Aussehen
define lcDropDown readingsGroup meineLightScene:!state Für die LightScene meineLightScene soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.
attr lcDropDown commands { state => 'scene:' } Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.
attr lcDropDown nonames 1 Keine Readingnamen
attr lcDropDown notime 1 Kein Timestamp

Schriftgrößen, Farben, Icons

Definition Erläuterungen
Schriftgröße, Farbe, Icons...
define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption Die readings state, power und consumption aller PCA301 Devices mit einer Zeile pro Device.
attr Verbrauch mapping %ROOM %ALIAS Der Raumname und der Alias werden als Zeilentitel verwendet
attr Verbrauch nameStyle style="font-weight:bold" Der Zeilentitel soll fett sein
attr Verbrauch style style="font-size:20px" Alles in einem größeren Font
attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"} Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.
attr Verbrauch valueIcon { state => '%devStateIcon' } Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.
attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'} Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün

Wertabhängige Farbgebung

Definition Erläuterungen
Wertabhängige Farben
Andere Werte - andere Farben
define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device.
attr wzTemperaturenRG group 3. Temperaturen Die readingsGroup kommt in eine Gruppe
attr wzTemperaturenRG noheading 1 noheading
attr wzTemperaturenRG nostate 1 nostate
attr wzTemperaturenRG notime 1 notime
attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" } Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.
attr wzTemperaturenRG valueStyle { if($DEVICE eq "Aussen" && $READING eq "temperature" && $VALUE > 30) { 'style="color:red"'}elsif($DEVICE eq "Aussen" && $READING eq "temperature" && $VALUE > 20) { 'style="color:orange"'}elsif($DEVICE eq "Aussen" && $READING eq "temperature" && $VALUE < 5) { 'style="color:blue"'}elsif($DEVICE eq "Wohnzimmer" && $READING eq "temperature" && $VALUE > 23) { 'style="color:red"'}elsif($DEVICE eq "Wohnzimmer" && $READING eq "temperature" && $VALUE > 21) { 'style="color:orange"'}elsif($DEVICE eq "Wohnzimmer" && $READING eq "temperature" && $VALUE < 20) { 'style="color:blue"'}elsif($DEVICE eq "Kasten_E_Geraete" && $READING eq "temperature" && $VALUE > 30) { 'style="color:red"'}elsif($DEVICE eq "Kasten_E_Geraete" && $READING eq "temperature" && $VALUE > 28) { 'style="color:orange"'}elsif($READING eq "humidity" && $VALUE > 65) { 'style="color:red"'}elsif($READING eq "humidity" && $VALUE > 60) { 'style="color:orange"'}else{'style="color:green"'} } Diverse Farbkombinationen sind möglich

Enigma Receiver

Definition Erläuterungen
Wertabhängige Farben
Wertabhängige Farben
define wzReceiverRG readingsGroup wzReceiver:,<Aktuell>,eventtitle,<Rest>,eventremaining_hr,<Dauer>,eventduration_hr wzReceiver:<Beschreibung>,eventdescription wzReceiver:,<Nächste>,eventtitle_next,<Start>,eventstart_next_hr,<Dauer>,eventduration_next_hr wzReceiver:,<HDD Kapazität>,hdd1_capacity,<Frei>,wzReceiver:hdd1_free wzReceiver:,<Lautstärke>,volume,<HDD>,hdd1_capacity,<Frei>,hdd1_free Mehrere readings des Device wzReceiver in mehreren Zeilen. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke, mute angezeigt. Farbige Anzeige des freien Speicherplatzes

Benötigt: ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: Enigma2 Receiver (Dreambox, VUplus etc.) steuern

attr wzReceiverRG group Fernseher Receiver Die readingsGroup kommt in eine Gruppe
attr wzReceiverRG mapping &nbsp; mapping wird auf &nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird
attr wzReceiverRG noheading 1 noheading
attr wzReceiverRG nostate 1 nostate
attr wzReceiverRG notime 1 notime
attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' } Die Beschreibung soll über 4 Spalten gehen
attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; } Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: 99 myUtils anlegen
attr wzReceiverRG valueStyle { if($READING eq "hdd1_free" && $VALUE < 200){ 'style="color:red"' }elsif( $READING eq "hdd1_free" && $VALUE < 500 ){ 'style="color:orange"' }elsif( $READING eq "volume" && ReadingsVal($DEVICE, "mute", "") eq "on" ){ 'style="color:red"' }else{ 'style="color:green"' } } Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke mute angezeigt.
sub
wzReceiverRGvalueFormat($$$)
{
  my ($DEVICE,$READING,$VALUE) = @_;
 
  if($READING eq 'hdd1_capacity') { 
    return "%.2f MB";
  } elsif( $READING eq 'hdd1_free') {
    return "%.2f MB";
  } elsif( $READING eq 'volume' ) {
    if( ReadingsVal($DEVICE, "mute", "") eq "on") {
      return "mute";
    } else {
      return "%i %%";
    }
  }
}
Dieser Teil kommt in die 99_myUtils.pm

Heizungswerte inklusive Batterie- und Fensterstatus

Definition Erläuterungen
Heizungswerte inklusive Batterie- und Fensterstatus
define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery Diverse readings aller Devices des Typs FHT.
attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' } Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.
attr Heizungswerte nameStyle style="color:yellow;font-weight:bold" Die Überschriften sollen gelb sein.
attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'} Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.

Heizungswerte inklusive Ventilposition

Definition Erläuterungen
Heizungswerte inklusive Statusinformationen (MAX!)
define Heizungswerte readingsGroup <%sani_heating>,<Ventil>,<Soll>,<Ist>,<MaxV>,<GID>,<Mode>,<Batterie> TYPE=CUL_HM:ValvePosition,desired-temp,measured-temp,R-valveMaxPos,groupid,mode,battery Diverse readings aller Devices des Typs MAX.
attr Heizungswerte mapping %ROOM Die Raumnamen werden angezeigt.
attr Heizungswerte nameStyle style="color:yellow;font-weight:bold" Die Überschriften sollen gelb (fett) sein.
attr Heizungswerte room Heizung Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.
attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" } Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.
attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'} Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!
attr Heizungswerte valueStyle { if($READING eq "temperature" && $VALUE > 20){ 'style="color:green;;font-weight:bold"' }elsif( $READING eq "temperature" && $VALUE <= 20 ){ 'style="color:blue"' }elsif( $READING eq "temperature" && $VALUE > 23 ){ 'style="color:red"' }else{ 'style="color:gray"' } } Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.
attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'} Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.

Heizungswerte, Status und Regelmöglichkeit

Definition Erläuterungen
Anzeige + Regelmöglichkeit
define Heizungswerte2 readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<{myUtils_HeizungUpDown($DEVICE,"up")}@desired-temp>,desired-new,<{myUtils_HeizungUpDown($DEVICE,"down")}@desired-temp>,window,battery Diverse readings aller Devices des Typs FHT.
attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold" Die Überschriften sollen gelb sein.
attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'} Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.
attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':} Nach dem Einstellen den Wert wieder ausblenden.
#Heizung regeln in readingsGroup
sub
myUtils_HeizungUpDown($$)
{
  my($DEVICE,$CMD) = @_;
  
  my $icon = $CMD;
  my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );
  $VALUE = ReadingsVal($DEVICE,"desired-temp","20" )
     if( !$VALUE || $VALUE == 0 );
  my $link;
  
  if( $CMD eq "up" ) {
    $icon = "control_arrow_upward";
    $VALUE += 1;
  
    if( $VALUE <= 24 ) {
      $icon .= "\@red";
      $link = "setreading $DEVICE desired-new $VALUE";
    }
  } elsif( $CMD eq "down" ) {
    $icon = "control_arrow_downward";
    $VALUE -= 1;
  
    if( $VALUE >= 18 ) {
      $icon .= "\@blue";
      $link = "setreading $DEVICE desired-new $VALUE";
    }
  }
  
  my $notify = "notifyHeizungUpDown";
  if( !defined($defs{$notify}) ) {
    CommandDefine(undef,
                   "$notify notify .*:desired-new.* "
                   ."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );
  }
  
  my $ret = "%$icon";
  $ret .= "%$link" if( $link );
  
  return $ret;
}

sub
myUtils_HeizungUpDownNotify($$)
{
  my($DEVICE,$VALUE) = @_;
  
  return if( $VALUE == 0 );
  
  my $at = "triggerHeizungUpDown_$DEVICE";
  CommandDelete(undef, $at) if( defined($defs{$at}) );
  CommandDefine(undef,
                "$at at +00:00:03 "
                ."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"
                ."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"
                ."fhem(\"setreading $DEVICE desired-new 00\");}" );
  
  return undef;
}
Dieser Teil kommt in die 99_myUtils.pm: Hiermit werden die Icons zum Ändern der gewünschten Temperatur dargestellt und im Bereich >=18 und <= 24 Grad anklickbar gemacht. Zwischen den Pfeilen wird der gerade eingestellte Wert angezeigt. Wenn dieser drei Sekunden nicht mehr geändert wurde wird die desired-temp auf diesen Wert gesetzt und die Anzeige zwischen den Pfeilen ausgeblendet.

Heizungswerte, Status, Steuerung und Wochenprofil

Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.

Todo: Überarbeiten: umstellen auf readingList oder setreading, label als readings in die readingsGroup selber stecken statt in einen extra dummy. oder !<reading> und mapping verwenden.
Definition Erläuterungen
Status, Steuerung und Wochenprofil
define d_label dummy
setreading d_label Heizung Heizung 
setreading d_label Temperatur Temperatur 
setreading d_label  Status Status 
setreading d_label Wochenplan Wochenplan 
setreading d_label Werktag Werktag 
setreading d_label Samstag Samstag 
setreading d_label Sonntag Sonntag 
setreading d_label Zeitraum1 Zeitraum 1 
setreading d_label Zeitraum2 Zeitraum 2 
Erzeugen der Readings im Device d_label. (Zeilenweise in die Befehlszeile eintragen.)

define rg_thermostate readingsGroup <>,Heizung@d_label,<|>,Temperatur@d_label,<|>,Status@d_label,<|>,Wochenplan@d_label,<|>,Werktag@d_label,<|>,Samstag@d_label,<|>,Sonntag@d_label,<|>,<> CUL_HM_HM_CC_RT_DN_......_Clima:<>,?alias,<|>,<Soll>,desired-temp,<Tag>,dayTemp@{rg($DEVICE."§clima")},impossible@{$DEVICE},<|>,controlMode,R-globalBtnLock@{rg($DEVICE."§device")},<|>,Zeitraum1@d_label,<|>,workday_period_1_start@{rg($DEVICE."§clima")},workday_period_1_stop@{rg($DEVICE."§clima")},<|>,saturday_period_1_start@{rg($DEVICE."§clima")},saturday_period_1_stop@{rg($DEVICE."§clima")},<|>,sunday_period_1_start@{rg($DEVICE."§clima")},sunday_period_1_stop@{rg($DEVICE."§clima")},<|>,impossible@{$DEVICE},<%system_fhem_update>,<br>,state@{rg($DEVICE."§device")},<%getConfig>,<|>,<Ist>,measured-temp,<Nacht>,nightTemp@{rg($DEVICE."§clima")},<|>,<Ventil>,ValvePosition,<|>,Zeitraum2@d_label,<|>,workday_period_2_start@{rg($DEVICE."§clima")},workday_period_2_stop@{rg($DEVICE."§clima")},<|>,saturday_period_2_start@{rg($DEVICE."§clima")},saturday_period_2_stop@{rg($DEVICE."§clima")},<|>,sunday_period_2_start@{rg($DEVICE."§clima")},sunday_period_2_stop@{rg($DEVICE."§clima")},<|>,impossible@{$DEVICE},impossible@{rg($DEVICE."§device")},<%burstXmit>

Diverse readings aller Devices CUL_HM_HM_CC_RT_DN_......_Clima, entsprechender d_climaControl (müssen vorher angelegt werden) und d_label.
attr rg_thermostate commands { 'desired-temp' => 'desired-temp:', 'dayTemp' => 'dayTemp:', 'controlMode' => 'trigger ntfy_rg $DEVICE controlMode', 'R-globalBtnLock' => 'trigger ntfy_rg $DEVICE globalBtnLock', 'workday_period_1_start' => 'workday_period_1_start:', 'workday_period_1_stop' => 'workday_period_1_stop:', 'saturday_period_1_start' => 'saturday_period_1_start:', 'saturday_period_1_stop' => 'saturday_period_1_stop:', 'sunday_period_1_start' => 'sunday_period_1_start:', 'sunday_period_1_stop' => 'sunday_period_1_stop:', 'rg_thermostate.system_fhem_update' => 'trigger ntfy_rg $DEVICE setTimeTable', 'rg_thermostate.getConfig' => 'set $DEVICE getConfig', 'nightTemp' => 'nightTemp:', 'workday_period_2_start' => 'workday_period_2_start:', 'workday_period_2_stop' => 'workday_period_2_stop:', 'saturday_period_2_start' => 'saturday_period_2_start:', 'saturday_period_2_stop' => 'saturday_period_2_stop:', 'sunday_period_2_start' => 'sunday_period_2_start:', 'sunday_period_2_stop' => 'sunday_period_2_stop:', 'rg_thermostate.burstXmit' => 'set $DEVICE burstXmit'} Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern ntfy_rg
attr rg_thermostate mapping { 'desired-temp' => , 'dayTemp' => , 'workday_period_1_start' => , 'workday_period_1_stop' => , 'saturday_period_1_start' => , 'saturday_period_1_stop' => , 'sunday_period_1_start' => , 'sunday_period_1_stop' => , 'nightTemp' => , 'workday_period_2_start' => , 'workday_period_2_stop' => , 'saturday_period_2_start' => , 'saturday_period_2_stop' => , 'sunday_period_2_start' => , 'sunday_period_2_stop' => } Ausblenden der Texte vor den DropDowns.

attr rg_thermostate nameStyle{($READING eq "Soll" ||$READING eq "Tag" ||$READING eq "%getConfig" ||$READING eq "Ist" ||$READING eq "Nacht" ||$READING eq "Ventil" )?'style="text-align:right"' :($READING eq "%burstXmit" )?'style="text-align:center"' :'style=""'}

Ausrichten der Überschriften die keine readings sind.
attr rg_thermostate nonames 1 Ausblenden der Device Namen.
attr rg_thermostate valueColumns { 'Heizung' => 'colspan="2"', 'Temperatur' => 'colspan="4"', 'Status' => 'colspan="2"', 'Werktag' => 'colspan="2"', 'Samstag' => 'colspan="2"', 'Sonntag' => 'colspan="2"', 'alias' => 'colspan="2"'} Diverse Readings sollen über mehrere Spalten dargestellt werden.
attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f °C", 'ValvePosition' => "%0.1f %%"} Formatierung für measured-temp und ValvePosition.
attr rg_thermostate valueIcon { 'controlMode.auto' => 'sani_heating_automatic@green', 'controlMode.set_auto' => 'sani_heating_automatic@orange', 'controlMode.manual' => 'sani_heating_manual@red', 'controlMode.set_manual' => 'sani_heating_manual@orange', 'R-globalBtnLock.on' => 'secur_locked@green', 'R-globalBtnLock.on ' => 'secur_locked@green', 'R-globalBtnLock.set_on ' => 'secur_locked@orange', 'R-globalBtnLock.off' => 'secur_open@red', 'R-globalBtnLock.off ' => 'secur_open@red', 'R-globalBtnLock.set_off ' => 'secur_open@orange'} Zuweisung der Icons.

attr rg_thermostate valueStyle{($READING eq "Heizung" ||$READING eq "Temperatur" ||$READING eq "Status" ||$READING eq "Wochenplan" ||$READING eq "Werktag" ||$READING eq "Samstag" ||$READING eq "Sonntag" )?'style="font-size:20px;;color:RoyalBlue;;text-align:center"' :($READING eq "alias" )?'style="font-size:11px;;font-weight:bold;;text-align:left"' :($READING eq "ValvePosition" &&$VALUE > 40 )?'style="font-weight:bold;;color:Orange;;text-align:left"' :($READING eq "desired-temp" ||$READING eq "measured-temp" )?'style="text-align:center"' :($READING eq "state" ||$READING eq "ValvePosition" )?'style="text-align:left"' :'style="text-align:right"'}

Ausrichten und Einfärben der Readings.

Heizungsteuerung für HM Wand- und Heizkörperthermostate

Dieses Beispiel wurde für HM-TC-IT-WM-W-EU / HM-CC-RT-DN Geräte erstellt. Verwendung anderer Thermostate wird ggf. Anpassungen erforderlich machen. Die Geräte werden nicht automatisch ermittelt, sondern sind einzeln angegeben. Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock. Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock. Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben.

Die Gerätenamen (EG_WZ_WT01_Climate / EG_WZ_WT01, EG_WZ_TT01_Clima / EG_WZ_TT01 / EG_WZ_TT02, OG_BZ_WT01_Climate / OG_BZ_WT01, OG_BZ_TT01_Clima / OG_BZ_TT01, OG_SZ_WT01_Climate / OG_SZ_WT01, OG_SZ_TT01_Clima / OG_SZ_TT01, OG_DZ_WT01_Climate / OG_DZ_WT01, OG_DZ_TT01_Clima / OG_DZ_TT01) müssen natürlich entsprechend angepasst werden.

Hinweis: Bei den Geräten muss das Attribut „expert“ auf "1_on" gesetzt werden, andernfalls fehlt das Reading „R-globalBtnLock“. Dies hätte zur Folge, dass in der Spalte Lock der batteryLevel dargestellt wird.

Definition Erläuterungen
Status, Steuerung und Wochenprofil
define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat>

EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \
<>,<>,<>,<>,<>,<>,<>,<> \
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \
<>,<>,<>,<>,<>,<>,<>,<> \
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \
<>,<>,<>,<>,<>,<>,<>,<> \
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01

ReadingsGoup anlegen.
attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',

"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}

Schrift fett setzen etc.
attr heatingInfo commands {

'heatingInfo.sollsetz'=>'desired-temp:5.0,12.0,18.0,19.0,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0',
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}

Heizungssteuerung ermöglichen

attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",
OG_BZ_TT01_Clima=>"&nbsp;;&nbsp;;&nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",
OG_SZ_TT01_Clima=>"&nbsp;;&nbsp;;&nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",
OG_DZ_TT01_Clima=>"&nbsp;;&nbsp;;&nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",
EG_WZ_TT01_Clima=>"&nbsp;;&nbsp;;&nbsp;;Regler1",EG_WZ_TT02_Clima=>"&nbsp;;&nbsp;;&nbsp;;Regler2",'desired-temp' => }

Gewünschte Namen definieren.

attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}
else{$VALUE=0}}}

Werte vorformatieren (für die Icon-Zuordnung).

attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D',
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}

Icons zuordnen.

attr heatingInfo valueStyle {if($READING eq "measured-temp")
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}
else{'style="color:rgb(12,251,12);;"'}}}

Farben (zu kalt: blau, zu warm: rot, ok: grün).

attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C",
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)",
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH",
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}

Messeinheiten und Zahlenwerte.

Readings aus zusätzlichen Devices

Im folgenden Beispiel wird gezeigt wie sich Readings zusätzlicher Devices zu einer Zeile mit mehreren Readings hinzufügen lassen. Diese zusätzlichen Devices können z.b. die unterschiedlichen Channel eines HomeMatic Gerätes sein. Im folgenden Beispiel wird der Name des zugehörigen Geräts dynamisch bestimmt.

Definition Erläuterungen
Anzeige + Regelmöglichkeit
define myTemp readingsGroup <Raum>,<Tist>,<Tsoll>,<Mode>,<Tnight>,<Tday>,<Hum>,<BatTC>,<Vist>,<Vsoll>,<Verr>,<BatVD> Thermostat.(WZ|OZ|AZ|Bad|Kueche|SZ|GZ|Bad.OG):measured-temp,desired-temp,controlMode,night-temp,day-temp,humidity,battery,ValvePosition@{valveOfDevice($DEVICE)},ValveDesired@{valveOfDevice($DEVICE)},R-valveErrorPos@{valveOfDevice($DEVICE)},battery@{valveOfDevice($DEVICE)} Broetje:ToutIst Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs.
attr myTemp mapping { 'Broetje' => 'Garten','Thermostat.AZ' => 'EG Arbeitszimmer','Thermostat.SZ' => 'OG Schlafzimmer','Thermostat.WZ'=>'EG Wohnzimmer','Thermostat.Kueche' => 'EG Küche','Thermostat.GZ' => 'OG Gästezimmer','Thermostat.Bad' => 'EG Bad','Thermostat.Bad.OG' => 'OG Bad','Thermostat.OZ' => 'EG Kaminzimmer','desired-temp' => '' } Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).
attr myTemp commands { 'desired-temp' => 'desired-temp:' } desired-temp soll per dropDown einstellbar sein.
attr myTemp nameStyle style="color:yellow" Die Überschriften sollen gelb sein.
attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'} Für den Batteriestand sollen jeweils Icons angezeigt werden.
attr myTemp valueFormat { 'measured-temp' => "%0.1f &deg;C",'ToutIst' => "%.1f &deg;C",'night-temp' => "%.1f &deg;C",'day-temp' => "%.1f &deg;C",'humidity' => "%.0f

%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }

Die Formatierung der Werte.
#namen des ventil device aus thermostat device ableiten
sub valveOfDevice ($) {
  my ($DEVICE) = @_;
  
  if ($DEVICE =~ m/AZ/) {
 	return "Ventil.".substr($DEVICE,11).".Nord";
  } else {
 	return "Ventil.".substr($DEVICE,11);  	
  }
}
Dieser Teil kommt in die 99_myUtils.pm: Hier wird aus dem Namen des Thermostaten der Name des zugehörigen Ventilantriebs abgeleitet.

Da im {...} Teil des <reading>@<device> Arguments keine Leerzeichen oder Kommas vorkommen dürfen ist es in der Regel das Einfachste die Funktionalität wie in diesem Beispiel in eine eigene Routine auszulagern. Mit ein paar 'Tricks' lässt es sich aber manchmal auch ohne Leerzeichen oder Kommas lösen und dann direkt in die Definition schreiben:...,ValvePosition@{$DEVICE=~s/Thermostat/Ventil/;$DEVICE;},...

Inhalte filtern

Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von valueFormat ausfiltern, bspw.:

attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }

In diesem Bsp. werden alle Zeilen/Devices, deren Value > 0 sind, angezeigt. Alle anderen werden als undef formatiert und erscheinen damit nicht im Listing.

Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. ReadingsGroup#Dynamische Inhalte).

Inhalte berechnen

Will man nur kleine Berechnungen machen und möchte diese aus irgendeinem Grund nicht in die 99_myUtils.pm auslagern (z.B. der Übersicht halber), so kann man die Berechnung auch direkt in valueFormat einbauen. Ein ganz einfaches Bsp. dazu ist das Filtern von Inhalten (s.o.).

Im konkreten Beispiel ist via CalDAV ein Abfallkalender eingebunden, der die folgenden Einträge erzeugt:

t_001_bdate 06.02.2017 2017-02-04 14:40:49
t_001_btime 00:00:00   2017-02-04 14:40:49
...
t_001_summary Gelber Sack 2017-02-04 14:40:49

Daraus lässt sich mit readingsGroup so direkt keine ordentliche Darstellung erzeugen. Gewünscht ist aber das folgende Format eines Zeileneintrags:

06.02.2017 Gelber Sack

Dies lässt sich durch eine noch einigermaßen kurze Berechnung erzeugen - längere Berechnungen sollte man definitiv in myUtils auslagern (vgl. hier). Der folgende Code filtert zusätzlich weitere nicht erwünschte Einträge aus und macht noch eine Wortanpassung:

# die readingsGroup reagiert nur auf summary-Einträge ( .* steht für eine beliebige Anzahl beliebiger Zeichen)

define Abfallkalender readingsGroup calvAbfallKalender:t_.*summary

attr Abfallkalender valueFormat {
  use Time::Local;;
  # alle Einträge Bio... und 4-wöchige Rest... ignorieren
  if (not $VALUE =~ /Bio/ and 
      not $VALUE =~ /Restmülltonne..4/) {
	# readingname für bdate zum summary erzeugen
	my $rBdate = $READING =~ s/summary/bdate/r;;
	# readingvalue für bdate auslesen
	my $vDate = ReadingsVal($DEVICE,$rBdate,"");;
	# wenn value 'tonne' enthält dieses entfernen
	if ($VALUE =~ /tonne/) {
	    $vDate . " " . substr($VALUE,0,index($VALUE,'tonne'));;
	} else {
	    "$vDate %VALUE";;
	}
  } else {
    undef;;
  }
}

Der Code in der cfg-Datei würde bei valueFormat zwischen den Hauptklammern immer ;;;; statt ;; und an jedem Zeilenende ein \ haben.

Dynamische Inhalte

readingsGroup mit umschaltbarem Inhalt 1
readingsGroup mit umschaltbarem Inhalt 2

Es ist möglich, den in einer readingsGroup dargestellten Inhalt dynamisch von zusätzlichen Bedingungen abhängig zu machen. Im folgenden Beispiel lässt sich einstellen, dass nur die Devices angezeigt werden, die einen bestimmten Zustand (hier: on/off, open/tilted/closed) haben. Hier wird zum Umschalten ein dummy, der direkt über der readingsGroup dargestellt wird, verwendet. Über das links und/oder commands lässt sich auch eine Darstellung erzeugen, bei der das Umschalten direkt innerhalb der readingsGroup möglich ist.

define LXrg dummy
attr LXrg group -
attr LXrg setList mode1:on,off mode2:open,closed,tilted
attr LXrg stateFormat 1=mode1 2=mode2
attr LXrg webCmd mode1:mode2

define rg readingsGroup Window.*:state Light.*:state
attr rg group -
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}

define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}

Enable/Disable Button am Beispiel eines WeekdayTimer

Dieses Beispiel zeigt die Anwendung einer readingsGroup, um im Frontend einen Enable/Disable Button für ein Objekt darzustellen. Für den WeekdayTimer gibt es hier spezielle Erweiterungen (set Routinen, um das Attribut disable zu setzen). Es gibt aber auch eine allgemeinere Variante (siehe diesen Forumsbeitrag) für alle Objekte, die das FHEM Attribut disable unterstützen.

Definition Erläuterungen
Enable/Disable Button
define rg_Timer_Wasser readingsGroup timer_Wasser_..:disabled,+DEF,<{rg_timer_Wasser_show_conditional($DEVICE,"nextUpdate")}@disabled>,<{rg_timer_Wasser_show_conditional($DEVICE,"nextValue")}@disabled> Definition der angezeigten Readings. Das Attribut disabled wird mit weiteren Einstellungen (commands) zum Button, +DEF zeigt die Definition, d.h. die Schaltzeiten, des Timers an. Die Readings nextUpdate und nextValue sollen nur angezeigt werden, falls der Timer aktiv ist. Hierfür sorgt eine Routine rg_timer_Wasser_show_conditional, die in der 99_myUtils.pm definiert wird. Das abschließende @disabled sorgt dafür, dass der LongPoll Mechanismus die Anzeige sofort ändert, wenn der Button betätigt wird.
attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }} Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt.
attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' } Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.
attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' } Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") ist, sorgt ein Klick auf den Button dafür, dass der Timer deaktiviert wird ("set $DEVICE disable").
sub rg_timer_Wasser_show_conditional($$)
{
  my ($DEVICE,$READING) = @_;
  return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? 
     ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";
}
Dieser Teil kommt in die 99_myUtils.pm: Hiermit wird das übergebene Reading des Timers nur angezeigt, wenn der Timer aktiv ist. Andernfalls wird der String "disabled" angezeigt.

Ändern von Attributen: Noch ein WeekdayTimer Beispiel

Emblem-question-yellow.svgDieses Beispiel benutzt Funktionen, die erst ab Modulversion 8761/16.6.2015 verfügbar sind.

Inzwischen ist es auch möglich das commands Mapping auf Attribute anzuwenden. Die Syntax ist die gleiche wie für die set Kommandos. Um das Beispiel übersichtlich zu halten werden hier die Werte und Icons auch für deaktivierte WeekdayTimer angezeigt.

Definition Erläuterungen
FHEMWidget für das 'disable' Attribut
define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable Definition der angezeigten Readings. Das Attribut disable wird mit weiteren Einstellungen (commands) zum Button. Durch das ! wird das Attribut auch dann angezeigt wenn es noch nicht gesetzt ist.
attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' } Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.
attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}' Vom nächsten Schaltpunkt wird nur die Zeit angezeigt.
attr rgTimer commands { disable => 'disable:' } Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.

Readings löschen

Es kann vorkommen, dass Readings angezeigt werden, die gar nicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbenannt hat, kann auch der alte Readingsname immer noch angezeigt werden. Solche Readings können mit der globalen Funktion deletereading gelöscht werden.

Achtung: Auf jeden Fall die commandref/deletereading dazu lesen!

Beispiel: Im HTTPMOD des Pollenflug war zuerst das reading04Name Graeser definiert und wurde später in reading04Name Gräser umbenannt. In der zugehörigen ReadingGroup wurden dann konsequent beide Varianten dargestellt - auch nachdem alle Alt-Einträge aus den Logs entfernt wurden. Erst ein deletereading Pollenflug Graeser in der FHEM-Befehlszeile hat das veraltete Reading entfernt.


Ausrichtung der Tabelle drehen (horizontal/vertikal)

Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, z.B. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (z.B. Allergy), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag Beitrag :

define Pollenflugvorhersage allergy <PLZ>
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red
attr Pollenflugvorhersage stateFormat fc1_maximum
attr Pollenflugvorhersage updateEmpty 1
attr Pollenflugvorhersage updateIgnored 1

# Pollen in Spalten, Tage in Zeilen
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \
Pollenflugvorhersage:fc1_day_of_week,fc1_Ampfer,fc1_Ambrosia,fc1_Beifuß,fc1_Birke,fc1_Buche,fc1_Eiche,fc1_Erle,fc1_Gräser,fc1_Hasel,fc1_Pappel,fc1_Roggen,fc1_Ulme,fc1_Wegerich,fc1_Weide \
Pollenflugvorhersage:fc2_day_of_week,fc2_Ampfer,fc2_Ambrosia,fc2_Beifuß,fc2_Birke,fc2_Buche,fc2_Eiche,fc2_Erle,fc2_Gräser,fc2_Hasel,fc2_Pappel,fc2_Roggen,fc2_Ulme,fc2_Wegerich,fc2_Weide \
Pollenflugvorhersage:fc3_day_of_week,fc3_Ampfer,fc3_Ambrosia,fc3_Beifuß,fc3_Birke,fc3_Buche,fc3_Eiche,fc3_Erle,fc3_Gräser,fc3_Hasel,fc3_Pappel,fc3_Roggen,fc3_Ulme,fc3_Wegerich,fc3_Weide \
Pollenflugvorhersage:fc4_day_of_week,fc4_Ampfer,fc4_Ambrosia,fc4_Beifuß,fc4_Birke,fc4_Buche,fc4_Eiche,fc4_Erle,fc4_Gräser,fc4_Hasel,fc4_Pappel,fc4_Roggen,fc4_Ulme,fc4_Wegerich,fc4_Weide \
Pollenflugvorhersage:fc5_day_of_week,fc5_Ampfer,fc5_Ambrosia,fc5_Beifuß,fc5_Birke,fc5_Buche,fc5_Eiche,fc5_Erle,fc5_Gräser,fc5_Hasel,fc5_Pappel,fc5_Roggen,fc5_Ulme,fc5_Wegerich,fc5_Weide \
Pollenflugvorhersage:fc6_day_of_week,fc6_Ampfer,fc6_Ambrosia,fc6_Beifuß,fc6_Birke,fc6_Buche,fc6_Eiche,fc6_Erle,fc6_Gräser,fc6_Hasel,fc6_Pappel,fc6_Roggen,fc6_Ulme,fc6_Wegerich,fc6_Weide \
Pollenflugvorhersage:fc7_day_of_week,fc7_Ampfer,fc7_Ambrosia,fc7_Beifuß,fc7_Birke,fc7_Buche,fc7_Eiche,fc7_Erle,fc7_Gräser,fc7_Hasel,fc7_Pappel,fc7_Roggen,fc7_Ulme,fc7_Wegerich,fc7_Weide
attr PollenAlarm nonames 1
attr PollenAlarm valueFormat %VALUE
attr PollenAlarm valueIcon %VALUE

# Tage in Spalten, Pollen in Zeilen
define PollenAlarmVertikal readingsGroup Pollenflugvorhersage:<Pollen>,fc0_day_of_week,fc1_day_of_week,fc2_day_of_week,fc3_day_of_week,fc4_day_of_week,fc5_day_of_week,fc6_day_of_week,fc7_day_of_week \
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide

Berechnungen

Emblem-question-yellow.svgDieses Beispiel benutzt Funktionen, die erst ab Modulversion 8761/16.6.2015 verfügbar sind.

Das Rechnen funktioniert über das Flag "$", mit dem eine Funktion angegeben werden kann, die auf beliebige Kombinationen von Zeilen, Spalten und einzelnen Zellen angewendet wird. Ähnlich wie in einer Tabellenkalkulation.

Ein Beispiel:

define rg readingsGroup .*:temperature rg:$avg

Damit wird eine readingsGroup über alle temperature Readings definiert. In einer zusätzlichen Zeile am Ende wird mit $avg der Durchschnittswert aller darüber liegenden Temperaturen angezeigt.

Das genaue Format: $<operator>[(<zellen>)] mit

  • <operator>: sum, avg, min, max, scalar, count oder der Name einer beliebigen anderen Funktion, die ein Array mit allen Werten übergeben bekommt und ein Ergebnis zurückliefert.
  • <zellen> ist eine durch Semikolon getrennte Liste aus <zeilen>:<spalten> Paaren.
  • <zeilen> und <spalten> sind jeweils eine Perl Liste, d.h. hier können
    • einzelne Werte,
    • durch Komma getrennte Aufzählungen,
    • mit .. angegebene Wertebereiche
    • sowie $ROW und $COLUMN als Bezeichner für die aktuelle Zelle
verwendet werden.

Alle Möglichkeiten sind kombinierbar. Die Zählung der Zeilen und Spalten beginnt bei 1. Eine nicht vorhandene Zeilenangabe wird durch den Bereich von Zeile 1 bis zur aktuellen Zeile ersetzt, eine nicht vorhandene Spalte durch die aktuelle Spalte.

Es ergeben sich somit unter anderem folgende Möglichkeiten:

  • $sum equivalent zu $sum(1..$ROW), $sum(:$COLUMN) und $sum(1..$ROW:$COLUMN) die Summe der Werte in der Spalte über der aktuellen Zelle.
  • $max($ROW:1..$COLUMN-1) Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)
  • $avg(1..$ROW:1) Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile
  • $scalar(:1) Anzahl der Werte in Spalte 1
  • $min(1..5:1,2,4) Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4

Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.

Die Ergebnisse werden im Weiteren wie normale Readings behandelt. Sie lassen sich von links oben nach rechts unten kaskadieren und lassen sich über valuePrefix, valueSuffix, valueFormat und valueStyle in der Darstellung beeinflussen. Also z.B. einfärben, als Balkendiagramm darstellen, ...

Mit Hilfe der Funktionalität zum auf- und zu-klappen von Teilen einer readingsGroup lassen sich z.B. im zusammengeklappten Zustand Summen, Extremwerte oder andere Ausreißer anzeigen und die Details nur beim Aufklappen zeigen.

Weitere Möglichkeiten:

  • Attribut firstCalcRow: Hiermit kann der Default für die Nummer der ersten Zeile vorgegeben werden (sofern im Ausdruck nichts genaueres angegeben ist). firstCalcRow sollte z.B. auf 2 gesetzt werden, wenn in der readingsGroup Spaltenüberschriften verwendet werden.
  • special <hr> um eine horizontale Linie über die volle Breite einzufügen
  • Über ein angehängtes @<alias> kann einem Rechenergebnis ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.
  • das alwaysTrigger Attribut kann jetzt auch den Wert 2 bekommen. Damit werden in der readingsGroup Readings für alle durch die Aggregation gebildeten Werte und entsprechende Events auch dann erzeugt wenn die readingsGroup nicht angezeigt wird. Wenn ein Alias-Name vergeben ist, wird dieser auch für den Reading-Namen verwendet.
  • Über den operator $count(<wert>)(<zellen>) um das Vorkommen von <wert> in den angegebenen Zellen zu zählen. <wert> kann enweder direkt der zu zählende Wert sein (ohne Anführungzeichen) oder eine in / eingeschlossene regex. Mit !<wert> kann das Nicht-Vorkommen von <wert> gezählt werden.

Ein interaktives Beispiel

Beispiel-readingsGroup mit Berechnungen

In drei dummy Objekten lässt sich jeweils ein Reading über einen Slider einstellen. In der darunter liegenden readingsGroup werden diese Readings und diverse daraus abgeleitete Werte dargestellt. Alle Readings und die daraus abgeleiteten Werte werden live per longpoll aktualisiert, wenn die slider bewegt werden.

  define t1 dummy
  attr t1 room rg
  attr t1 setList state:slider,-10,1,30
  attr t1 webCmd state
  define t2 dummy
  attr t2 room rg
  attr t2 setList state:slider,-10,1,30
  attr t2 webCmd state
  define t3 dummy
  attr t3 room rg
  attr t3 setList state:slider,-10,1,30
  attr t3 webCmd state

  define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\
  t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\
  <hr>\
  rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\
  <hr>\
  t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\
 
  attr rg nonames 1
  attr rg room rg
  attr rg style style='text-align:center'
  attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }
  attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'Σ; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'∅; ', 'rg.count' => '#(X): ' }
  attr rg valueSuffix { state => '°;C' }

Links und Trigger

readingsGroup mit Link

readingsGroup mit Link

Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten

<{appendTrigger($DEVICE,"clear","Alle löschen")}>

und der folgenden appendTrigger Definition in 99_myUtils.pm um einen Link erweitern, der ein Event auslöst, an das z.B. ein notify gehängt werden kann, um die Verbrauchszähler der PCA301 Dosen zurückzusetzen.

define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear
use vars qw($FW_ME);
use vars qw($FW_subdir);
sub
appendTrigger($$$)
{
  my ($name,$trigger,$label) = @_; 

  my $ret .= "</table></td></tr>";

  my $link = "cmd=trigger $name $trigger";
  my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";
  $ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";

  return ($ret,0);
}

Wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:

{myUtils_refresh("WEB")}

mit folgendem code in 99_myUtils.pm:

sub                                                                                     
myUtils_refresh($)                                                                      
{                                                                                       
  my ($name) = @_;                                                                      
                                                                                        
  FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );
}


Ein weiteres Beispiel für 'custom links und trigger' findet sich in diesem Forenbeitrag: dort wird damit eine readingsGroup dynamisch umgeschaltet, um nur die eingeschalteten, nur die ausgeschalteten oder alle Lampen anzuzeigen.

sub rg

Damit beim Klicken auf ein Icon oder einen Text in einer readingsGroup etwas passiert ist es möglich dies über das commands Attribut auf ein 'trigger ntfy_rg $DEVICE $READING' oder Ähnliches zu mappen. Anlegen des ntfy_rg notify

define ntfy_rg notify ntfy_rg {rg($EVENT)}

Folgender Code muss noch in de 99_myUtils.pm

sub rg($){
  my @input    = split(/[§\s]+/,shift);
  my $device   = $input[0];
  my $function = $input[1];

if($function eq "clima"){
  my $room =  AttrVal($device, 'room', 'undef');
  $room =~ s/\D//g;
  
  return(("d_climaControl_".$room));
}
elsif($function eq "device"){
  return InternalVal($device,"device","device error");
}
elsif($function eq "controlMode"){
  my $controlMode = ReadingsVal($device,"controlMode","controlMode error");

  if($controlMode ~~ /manual/)
    {fhem("set $device controlMode auto")}
  elsif($controlMode ~~ /auto/)
    {fhem("set $device controlMode manual")};
}
elsif($function eq "globalBtnLock"){
  my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");

  if($globalBtnLock ~~ /off/){
    {fhem("set $device regSet globalBtnLock on")}
    {fhem ("set $device getConfig")}
  }
  elsif($globalBtnLock ~~ /on/){
    {fhem("set $device regSet globalBtnLock off")}
    {fhem ("set $device getConfig")}
  };
}
elsif($function eq "state"){
  my $state = Value($device);

  if($state ~~ /off/){
    {fhem("set $device on")}
  }
  elsif($state ~~ /on/){
    {fhem("set $device off")}
  };
}
elsif($function eq "setTimeTable"){
  my $room         =  AttrVal($device, 'room', 'undef');
  $room         =~ s/\D//g;
  my $climaControl = ("d_climaControl_".$room);
  my $dayTemp           = ReadingsVal( $climaControl, "dayTemp"          , 21.0    );
  my $nightTemp         = ReadingsVal( $climaControl, "nightTemp"        , 17.0    );
  my $workday_period_1_start  = ReadingsVal( $climaControl, "workday_period_1_start"  , "06:30" );
  my $workday_period_1_stop   = ReadingsVal( $climaControl, "workday_period_1_stop"   , "18:00" );
  my $workday_period_2_start  = ReadingsVal( $climaControl, "workday_period_2_start"  , "24:00" );
  my $workday_period_2_stop   = ReadingsVal( $climaControl, "workday_period_2_stop"   , "24:00" );
  my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );
  my $saturday_period_1_stop  = ReadingsVal( $climaControl, "saturday_period_1_stop"  , "12:00" );
  my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );
  my $saturday_period_2_stop  = ReadingsVal( $climaControl, "saturday_period_2_stop"  , "24:00" );
  my $sunday_period_1_start   = ReadingsVal( $climaControl, "sunday_period_1_start"   , "24:00" );
  my $sunday_period_1_stop    = ReadingsVal( $climaControl, "sunday_period_1_stop"    , "24:00" );
  my $sunday_period_2_start   = ReadingsVal( $climaControl, "sunday_period_2_start"   , "24:00" );
  my $sunday_period_2_stop    = ReadingsVal( $climaControl, "sunday_period_2_stop"    , "24:00" );

  {fhem("set $device tempListMon prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListTue prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListWed prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListThu prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListFri prep $workday_period_1_start  $nightTemp $workday_period_1_stop  $dayTemp $workday_period_2_start  $nightTemp $workday_period_2_stop  $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListSat prep $saturday_period_1_start $nightTemp $saturday_period_1_stop $dayTemp $saturday_period_2_start $nightTemp $saturday_period_2_stop $dayTemp 24:00 $nightTemp")};
  {fhem("set $device tempListSun exec $sunday_period_1_start   $nightTemp $sunday_period_1_stop   $dayTemp $sunday_period_2_start   $nightTemp $sunday_period_2_stop   $dayTemp 24:00 $nightTemp")};
}
}

Hier sind die benötigten CodeBlöcke für Heizungswerte, Status, Steuerung und Wochenprofil enthalten, aber auch um state zu triggern.

Sonstiges

In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.

Lesbar machen

Für die meisten Attribute gilt:

  • Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) 99_myUtils auszulagern und diese aufzurufen:
attr <name> valueStyle {myValueToFormat($READING,$VALUE)}
  • code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:
attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }
  • Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:
if( $READING eq ... ) {
  return xxx if( $VALUE < 1 );
  return yyy if( $VALUE < 1.5 );
  return zzz;
} elsif( $READING eq ... ) {
  ...
}

Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.

readingsGroup in einer Gruppe

Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen:

attr <rgName> style style="border:0px;background:none;box-shadow:none"

Für die readingsGroup rgName wird der Darstellungsstil verändert.

Anwendungs-Bsp: Pollenflug

Einfache Balkendiagramme

readingsGroup mit Balken

Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:

attr <rgName> valueStyle style="width:200px; text-align:center; border: 1px solid #ccc; background:-webkit-linear-gradient(left, red $VALUE%, rgba(0,0,0,0) $VALUE%)"

Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.

Diese direkte Definition des valueStyle ist allerdings sehr unflexibel - bspw. müsste der $VALUE zufällig max 100 erreichen und es darf nur ein Browsertyp eingesetzt werden, damit alles sauber funktioniert.

Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die 99_myUtils.pm, die den valueStyle dynamisch generiert, bspw.:

sub Balkenanzeige($) 
{
    # Zuweisung der übergebenen Variablen
    my ($val) = @_;

    # Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)
    my $maxValue = 3;

    # Normalisierung auf 100%-Wert
    my $percent = $val / $maxValue * 100;

    # Definition des valueStyles
    my $stylestring = 'style="'.
        'width: 200px; '.
	'text-align:center; '.
	'border: 1px solid #ccc ;'. 
	'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.
	'background-image:    -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. 
	'background-image:     -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. 
	'background-image:      -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. 
	'background-image:         linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';

    # Rückgabe des definierten Strings
    return $stylestring;
}

Der Aufruf sähe dann wie folgt aus:

attr <rgName> valueStyle { Balkenanzeige($VALUE) }

Die einzelnen Werte des $stylestring haben folgende Bedeutungen:

  • width - Breite des Balkenrahmens
  • text-align - Ausrichtung des Texts
  • border - Format des Balkenrahmens
  • background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst
    • linear-gradient - css-Funktion zur Erstellung von Farbverläufen (*)
      • left - linksbündiger Balken
      • red x% - roter Balken x% breit
      • rgba(0,0,0,0) x% - farbloser Teil startet bei x%

(*) linear-gradient wird in verschiedenen Browsern unterschiedlich umgesetzt. Deshalb sollten immer alle Varianten zusammen angegeben werden, damit die Darstellung auf allen Browsern funktioniert. (vgl. Link unten)

Weitere Infos zu:

Anwendungs-Bsp: Pollenflug

readingsGroup Styling mit CSS

Jede readingsGroup lässt sich durch CSS individuell stylen.

Allgemeines

Damit der eigene CSS Code nach einem Update der FHEM-Style Dateien vorhanden bleibt, ist es notwendig eine eigene .css Datei (z.B. ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis fhem/www/pgm2/ zu kopieren. Anschließend muss in der FHEMWEB Instanz das Attribut CssFiles auf z.B. pgm2/ios7ReadingsGroups.css gesetzt werden.

Erweiterte Device Übersicht

Diese ReadingsGroup ist an der FHEMWEB Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zur Detail-Seite der ReadingsGroup und Links zu der jeweiligen Device-Detail-Seite, dargestellt.

Device ReadingsGroup ohne CSS
Device ReadingsGroup mit CSS
Definition
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\
attr rg_devices noheading 1
attr rg_devices nonames 1
attr rg_devices notime 1
attr rg_devices room ReadingsGroup Styling
attr rg_devices style class="block wide rgDevices"
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh"  }
attr rg_devices valueIcon { state => '%devStateIcon' }

Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötig das Attribut style anzupassen.

Definition Erläuterungen
attr <rgName> style class="block wide rgDevices" Die Klassen block und wide müssen eingetragen werden. Der Name der nachfolgenden Klasse, hier rgDevices, ist frei wählbar.
Funktion rgLink()

Die Funktion rgLink($name,$action,$label) liefert einen Link mit dem Namen $label zurück. Der Code gehört in die 99_myUtils.pm.

  • $name - Name des Device das aufgerufen werden soll
  • $action - Aktion die Ausgeführt werden soll.
    • konfigurieren erzeugt den kleinen Details Button links oben der einen zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut noheading gesetzt ist
    • detail erzeugt einen Link zu Device-Detail Seite
  • $label - Link-Name
sub rgLink($$$){
  my ($name,$action,$label) = @_; 
  my $link = "";
  my $fhemLink = "";
  my $txt = "";
  my $ret = "";
  my $divStyle = "";
  my $aStyle = "";
  
  # FHEM Variablen einbinden
  use vars qw($FW_ME);
  use vars qw($FW_subdir);
  use vars qw($FW_ss);
  use vars qw($FW_tp);

  if( $action eq "konfigurieren" ){
    $fhemLink  = "detail=$name";
    $divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";
  }
  elsif( $action eq "detail" ){
    $fhemLink  = "detail=$name";
    $divStyle = "cursor:pointer;display:inline;";
  }

  $link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';
  $txt  = '<div style="' . $divStyle . '">' . $link . '</div>';
  $ret  = "$txt";
  
  return $ret;
}
Info green.pngTipp Verwende zum Bearbeiten der eigenen .css Dateien entweder den Codemirror Editor oder einen eigenen Editor mit Syntax Highlighting . Das hilft bei der Fehlersuche enorm.


Styling

Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenem Editor bearbeitet werden.

ios7ReadingsGroups.css:

/*  Readings Groups Devices */
table.rgDevices tr td{ text-align: center; }
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }
table.rgDevices tr td:first-child{  /* 1. Spalte */ width: 45px; text-align: center; }
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%;  text-align: left; }
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }

Auf Portrait / Landscape Modus des Smartphone unterscheiden

Dieses Beispiel ist an das obige Beispiel Erweiterte Device Übersicht angelehnt.

Device ReadingsGroup im Portrait Modus
Device ReadingsGroup im Landscape Modus
Allgemeines

Mit CSS ist man in der Lage auf die aktuelle Bildschirmlage zu reagieren. Alle Anweisungen die in diesen beiden Funktionen zwischen den beiden { } stehen, werden je nach Bildschirmlage aufgerufen

/* Portrait Modus */
@media all and (orientation:portrait) { }

/* Landscape Modus */
@media all and (orientation:landscape) { }
Styling
Info green.pngInfo
  • width: xx% ändert die Breite der Spalte
  • display: none blendet die Spalte aus

In der FHEMWEB_phone Instanz muss wie hier beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css

ios7smallscreenReadingsGroups.css

/* landscape und portrait modus */
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }

/* Portrait Modus */
@media all and (orientation:portrait) {
  table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }
  table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }
  table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }
  table.rgDevices tr td:nth-child(6){ width: 0; display: none; }	
  table.rgDevices tr td div a svg{ margin-left: 90px; }
}

/* Landscape Modus */
@media all and (orientation:landscape) { 
  table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }
  table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }
  table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }	
}

Plots im Portrait Modus des Smartphones ausblenden

Device ReadingsGroup im Portrait Modus
Plot nur im Landscape

Um den Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie hier beschrieben folgendes ein:

@media all and (orientation:portrait) {
  .SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }
}