http://wiki.fhem.de/w/api.php?action=feedcontributions&user=Fabian&feedformat=atomFHEMWiki - Benutzerbeiträge [de]2024-03-29T08:07:27ZBenutzerbeiträgeMediaWiki 1.39.3http://wiki.fhem.de/w/index.php?title=Plots_erzeugen&diff=38992Plots erzeugen2024-01-22T12:33:16Z<p>Fabian: /* Links / Beispiele */ Link zum Artikel Plot-Abriss vermeiden eingefügt</p>
<hr />
<div>'''Plots erzeugen'''<br />
<br />
== .gplot-Editor ==<br />
<br />
FHEM verfügt über einen ".gplot-Editor" (auch als Ploteditor bezeichnet), um die .gplot-Datei zur Erstellung eines Plots menügeführt zu generieren. Ein manuelles Anlegen der .gplot-Datei ist für Spezialisten und normalerweise nicht notwendig. Der .gplot-Editor sollte für Standardfälle grundsätzlich verwendet werden. <br />
<br />
Details zum .gplot-Editor können im Ankündigungshinweis im {{Link2Forum|Topic=11275|Message=75594|LinkText=FHEM-Forum}} nachgelesen werden.<br />
<br />
Zur Einarbeitung in die Funktionsweise des .gplot-Editor existieren ausführliche, bebilderte Beispiele:<br />
<br />
*Grundlegendes Beispiel zur Erzeugung von Plots:<br />
:* [[Buderus_Web_Gateway#Mit_FileLog|Schrittweises Beispiel für Temperaturkurven]]<br />
<br />
*Spezielle Erläuterungen/Hinweise zur Erzeugung von Plots mit Status: <br />
:* [[EnOcean-STM-250-Fenster-Türkontakt#Türstatus in einem Plot darstellen|Schrittweises Beispiel bei Kontakten]], <br />
:* [[EnOcean-D-452-FU-EBIM-Aktor-2fach#Aktorstatus_in_einem_Plot_darstellen|Schrittweises Beispiel zum Aktorstatus]]<br />
:* {{Link2Forum|Topic=12945|Message=78887|LinkText=FHEM-Forum}}<br />
:* {{Link2Forum|Topic=43563|Message=354955|LinkText=Plots mit mehr als 2 Status}}<br />
<br />
Verhinderung von Perl-Warnungen bei LogFiles mit unterschiedlicher Spaltenanzahl in Log-Zeilen: {{Link2Forum|Topic=27835}}<br />
<br />
<big>'''Achtung'''</big>:<br />
{{Randnotiz|RNTyp=Info|RNText=Das in diesem Abschnitt "Achtung" beschriebene Problem ist seit dem FHEM-Update vom 06.04.2015 nicht mehr relevant. Der Befehl <code>copyGplotFile</code> ist seitdem nicht mehr notwendig, da FHEM ihn automatisch ausführt (Siehe {{Link2Forum|Topic=35764|Message=282728|LinkText=FHEM-Forum}}). }}<br />
Verwenden Sie diesen Editor nicht, wenn das FHEM-Device bereits angelegt ist und Sie für dieses Device ein bestehendes, allgemeines gplot-File verwenden, das auch für andere Devices benutzt wird. Beim Abspeichern wird ein Filter im gplot-File gesetzt, das das gplot-File nur für genau dieses Device verwendbar macht. <br />
<br />
Beispiel:<br />
<br />
aus <br />
<br />
#FileLog 4:::<br />
<br />
wird<br />
<br />
#FileLog 4:DS2423.energy_a\x3a::<br />
<br />
in dem entsprechenden gplot-File.<br />
<br />
Die anderen Devices, die evtl. dieses gplot-File verwenden, haben danach keine funktionierende Plot-Anzeige mehr. Bevor also etwas geändert wird, sollte mit <br />
<br />
set weblink_irgendwas copyGplotFile<br />
<br />
ein Duplikat angelegt werden, das ausschließlich für diesen Plot verwendet wird. Der Befehl kann unterhalb des ersten Kasten per Dropdown ausgewählt werden.<br />
<br />
== Individuell / Manuell ==<br />
<br />
'''Vorbemerkungen:'''<br />
<br />
* FHEM bediente sich früher für die Erstellung der Plots des Programms ''Gnuplot'' [http://www.gnuplot.info/]. Hierbei reichen die "einfacheren" Funktionalitäten dieses Programms aus (''Gnuplot'' kann noch viel mehr). <br />
* aktuelle FHEM-Versionen haben die Plot-Funktionen (angelehnt an die Plot-File-Syntax von Gnuplot) integriert.<br />
* die Beispieldateien für die in FHEM integrierten Plots finden Sie in Ihrem FHEM-Programmordner unter ''www/gplot''.<br />
* Angaben wie <SIZE>, <OUT>, <L1>, <IN> usw. im Plot-File sind Platzhalter bzw. Feldbezeichner für Fhem. Diese sind case-sensitive (Groß-/Kleinschreibung beachten).<br />
* Weitere Möglichkeiten Plots anzupassen und zu ergänzen bietet das FHEM-Hilfsmodul [[LogProxy|logProxy]].<br />
<br />
<br />
<br />
Ein Beispiel (''temp4hum4.gplot'') aus diesem Verzeichnis: <br />
<syntaxhighlight lang="gnuplot" style="width:500px;"><br />
# Attribute 'small' is useful for gnuplot/-scroll only,<br />
# if plotsize is less than 800,400<br />
#set terminal png transparent small size <SIZE> crop<br />
<br />
set terminal png transparent size <SIZE> crop<br />
<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set ytics nomirror<br />
set y2tics<br />
#set ytics<br />
set title '<L1>'<br />
set grid xtics y2tics<br />
<br />
set y2label "Temperature in C"<br />
set ylabel "Humidity (%)"<br />
<br />
#FileLog 4:temperature:10:<br />
#FileLog 4:humidity:50:<br />
<br />
plot \<br />
"< egrep 'temperature' <IN>"\<br />
using 1:4 axes x1y2 title 'Measured temperature' with lines,\<br />
"< egrep 'humidity' <IN>"\<br />
using 1:4 axes x1y1 title 'Humidity (%)' with lines\<br />
</syntaxhighlight> <br />
<br />
Die Zeilen, die mit ''set'' beginnen, beeinflussen wesentlich das Erscheinungsbild und Aussehen Ihrer Plots (Achsenbeschriftungen, Skalen usw.). Dabei sollten Sie die Zeilen, die eine Angabe zwischen "<" und ">" enthalten, zunächst unverändert lassen. Weitere (ausführliche) Hinweise (zu Gnuplot!) finden Sie in einer [http://www.home.uni-osnabrueck.de/elsner/Skripte/gnuplot.pdf PDF-Datei]. Eingeschränktere, aber für die meisten Belange von FHEM ausreichende Infos finden Sie auf [http://www.aurbacher.net/gnuplot/gnuplot.html dieser Web-Seite].<br />
<br />
=== Benutzung der Variablen === <br />
{| class="wikitable" <br />
! Variable <br />
! Nutzung in gplot-File<br />
! Füllung mit inhalt in fhem.cfg<br />
|- <br />
| <TL> <br />
| set title '<TL>' <br />
| attr weblink title "Dies füllt den Platzhalter <TL>" <br />
|-<br />
| <L1> <br />
| set xlabel '<L1>' <br />
| attr weblink label "Dies füllt das Label <L1>" <br />
|-<br />
| <L2> <br />
| set title '<L2>' <br />
| attr weblink label "Dies füllt das Label <L1>"::"Dies füllt das Label <L2>" <br />
|}<br />
<br />
=== Welche Daten werden dargestellt ===<br />
<br />
Die Zeilen<br />
<br />
#FileLog 5::0:<br />
#FileLog 14::0:<br />
<br />
in einer gplot-Datei tragen zwar zu Beginn das Kommentarzeichen "#", jedoch handelt es sich durchaus nicht um solche. Vielmehr trifft man mit den Werten hinter ''FileLog'' Vorgaben, welche Werte wie von FHEM an ''gnuplot'' zwecks grafischer Darstellung übergeben werden.<br />
<br />
Im o.a. Beispiel werden das 5. und das 14. Wertfeld (voneinander getrennt durch ein Leerzeichen (Blank)) an gnuplot weiter gegeben.<br />
<br />
Eine dazu passende Log-Dateizeile könnte beispielsweise so aussehen<br />
<br />
2013-11-14_17:32:00 2013-Nov-14 17:32:00 17.9 5.8 4.9 58 94 0.0 0.0 N 5.8 572.91 1015.200<br />
----1. Feld-------- --2. Feld-- --3.---- -4.- -5. -6. 7. 8. -9. 10. 11 12 --13.- --14.---<br />
<br />
^ ^<br />
werden ausgewertet --| --|<br />
<br />
Diese Parameter können auch als Attribut übergeben werden:<br />
<br />
attr weblink plotfunction "FileLog 5::0:"<br />
<br />
Anhand der Anmerkungen wird hoffentlich die Wirkungsweise deutlich. Zu den restlichen - optionalen - Parametern hinter ''FileLog'' wird zunächst auf die {{Link2CmdRef|Anker=FileLogget}} verwiesen.<br />
<br />
=== Datum und Zeit ===<br />
<br />
'''Anmerkungen / Hinweise:'''<br />
<br />
FHEM erwartet das Datum '''und''' die Uhrzeit der Log-Dateieinträge '''zwingend''' an <ins>erster Stelle</ins> der Datenzeile und zwar im Format<br />
<br />
<code>JJJJ-MM-TT_SS:mm:ss</code><br />
<br />
wobei<br />
<br />
* JJJJ die 4-stellige Jahreszahl<br />
* MM der 2-stellige Monat (ggfls. mit Vornull)<br />
* TT der 2-stellige Tag (ggfls. mit Vornull)<br />
* SS die 2-stellige Stunde (ggfls. mit Vornull)<br />
* mm die 2-stellige Minute (ggfls. mit Vornull)<br />
* ss die 2-stellige Sekunde (ggfls. mit Vornull)<br />
<br />
bedeutet. Bitte beachten Sie auch die Stelle der Zeichen "-", "_" und ":". Stehen diese nicht an den angegebenen Stellen, wird die entsprechende Zeile beim Erzeugen des Plots nicht beachtet. Ggfls. wird gar kein Plot angezeigt.<br />
<br />
Eine Änderung/Anpassung der *.gplot-Datei in der Zeile<br />
<br />
set timefmt "..."<br />
<br />
hat auf dieses Verhalten von FHEM '''keine''' Auswirkungen, sondern nur auf die Darstellung von Datum und Zeit durch ''Gnuplot'' .<br />
<br />
Dazu ein Beispiel:<br />
<br />
Mit<br />
<br />
2013-11-14_17:32:00 2013-Nov-14 17:32:00 17.9 5.8 4.9 58 94 0.0 0.0 N 5.8 572.91 1015.200 <br />
<br />
kann FHEM etwas anfangen. Mit <br />
<br />
20131114173200 2013-Nov-14 17:32:00 17.9 5.8 4.9 58 94 0.0 0.0 N 5.8 572.91 1015.200 <br />
<br />
oder <br />
<br />
14.11.2013 17:32 2013-Nov-14 17:32:00 17.9 5.8 4.9 58 94 0.0 0.0 N 5.8 572.91 1015.200 <br />
<br />
dagegen nicht.<br />
<br />
Im ersten Fehler-Beispiel fehlen die notwendigen Trennzeichen, im zweiten Fehler-Beispiel ist die Reihenfolge im Datum verkehrt, außerdem werden die falschen Trenner verwendet. Zudem fehlen die Sekunden.<br />
<br />
=== Plot der letzten 24 Stunden statt des aktuellen Tages ===<br />
<br />
Hierzu kann man in der ''Fhem.cfg'' für die Einträge <br />
<br />
define WEB FHEMWEB 8083 global<br />
<br />
das Attribut<br />
<br />
attr WEB endPlotNow 1<br />
<br />
setzen. Gleiches geht auch für ''WEBphone'' und ''WEBtablet''. Da muss es dann lauten<br />
<br />
attr WEBphone endPlotNow 1<br />
<br />
bzw.<br />
<br />
attr WEBtablet endPlotNow 1<br />
<br />
Das Attribut gilt dann aber für '''alle''' Plots der jeweiligen Ansichten. Wenn man wieder zurück zu den Plots ab jeweils 00:00 Uhr des aktuellen Tages möchte, löscht man dieses Attribut wieder bzw. setzt es auf den Wert "0".<br />
<br />
=== Legende links platzieren ===<br />
<br />
Gerade im Verbund mit dem Attribut ''endPlotNow'' macht das seit dem 11.01.2015 neue Attribut ''captionLeft'' Sinn, da dann die Legende nicht mehr rechts oben, sondern links oben im Plot erscheint. Dadurch wird die Sichtbarkeit der aktuellen Werte verbessert.<br />
<br />
== Links / Beispiele ==<br />
Hier finden sich weitere Beispiele zur Plot-Erstellung:<br />
* [[Creating Plots]]<br />
* [[Buderus Web Gateway#Beispiel für Plot]]<br />
* [[Wetter und Wettervorhersagen#Erstellen passender gplot-Dateien]]<br />
* [[Vitoconnect#SVG_Graphen_aus_FileLog_erstellen]]<br />
* [http://lowrank.net/gnuplot/intro/style-e.html Erklärung für die Linetypes]<br />
* [[Plot-Abriss vermeiden]]<br />
<br />
[[Kategorie:FAQ]]<br />
[[Kategorie:HOWTOS]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=FHT80b&diff=38609FHT80b2023-09-22T09:22:09Z<p>Fabian: /* Bekannte Probleme */ Verbindungsproblem zur Zentrale ergänzt (Lösung: Reset im FHT)</p>
<hr />
<div>{{Infobox Hardware<br />
|Bild=FHT80b.jpg<br />
|Bildbeschreibung=FHT80b<br />
|HWProtocol=FHT<br />
|HWType=Empfänger<br />
|HWCategory=FHT<br />
|HWComm=868,35 MHz<br />
|HWChannels=1<br />
|HWVoltage=3 V<br />
|HWPowerConsumption=(ca. 2 Jahre)<br />
|HWPoweredBy=2x AA<br />
|HWSize=100 x 60 x 60 mm<br />
|HWDeviceFHEM=11_FHT8V.pm<br />
|HWManufacturer=ELV / eQ-3}}<br />
<br />
Der [[FHT80b]] ist ein programmierbarer Raumthermostat, der bis zu 8 Stellantriebe [[FHT8v]] steuern kann.<br />
<br />
'''Achtung: Dieses Gerät ist abgekündigt (wird nicht mehr hergestellt).'''{{Link2Forum|Topic=60219}}<br />
<br />
== Features ==<br />
Lokal programmierbare Tages- und Nachttemperatur, die pro Tag mit 4 Schaltpunkten programmiert werden kann.<br />
Zusätzliche Anbindung eines Tür/Fensterkontaktes [[FHT80TF]] zur Absenkung der Temperatur auf separat einstellbaren Wert bei offenem Fenster (windowopen-temp). <br />
<br />
== Readings ==<br />
{| class="wikitable" <br />
! Parameter <br />
! Wertbeispiel <br />
! Erklärung<br />
|- <br />
| actuator <br />
| 0% <br />
| Position des Stellantriebes in&#160;%<br />
|- <br />
| battery <br />
| ok <br /> low<br />
| Ladezustand der Batterien<br />
|- <br />
| mode <br />
| auto <br /> manual <br /> holiday_short <br /><br />
| Funktionsmodus (auto, manuell oder Urlaub/Party)<br />
|- <br />
| state <br />
| measured-temp: 20.9 <br />
| Ist-Temperatur in ° (C oder F in FHT80B wählbar)<br />
|- <br />
| desired-temp <br />
| 21.0 <br />
| Solltemperatur in ° (C oder F in FHT80B wählbar)<br />
|- <br />
| holiday1 <br />
| 126 <br />
| Endzeit der Urlaubs-/Partyfunktion. Uhrzeit in Minuten seit 00:00 geteilt 10 (im Beispiel 21:00 Uhr)<br />
|- <br />
| holiday2 <br />
| 31 <br />
| Tag im Monat an der die Urlaubs-/Partyfunktion endet <br />
|- <br />
| lowtemp <br />
| ok <br /> warn<br />
| Untertemperatur-Alarm: Im Raum wird der Temperatur-Sollwert nicht erreicht<br />
|- <br />
| manu-temp <br />
| <br />
| Solltemperatur bei Manuell-Modus<br />
|- <br />
| night-temp <br />
| <br />
| Solltemperatur bei Absenkung<br />
|- <br />
| warnings <br />
| none <br /> Battery low <br /> Temperature too low <br /> Fault on window sensor<br />
| Auflistung der Fehler<br />
|- <br />
| window <br />
| closed <br /> open <br />
| Statusmeldungen vom FHT80-TF<br />
|- <br />
| windowsensor <br />
| ok <br /> fault<br />
| fault, wenn ein angemeldeter Fenstermelder nicht erreicht werden kann.<br />
|- <br />
| windowopentemp <br />
| 9.0 <br />
| Solltemperatur bei offenem Fenster<br />
|- <br />
| year <br /><br />
month<br /><br />
day<br /><br />
hour<br /><br />
minute<br />
| <br />
| Zeitangaben für interne Uhr<br />
|- <br />
| mon-from1 <br /><br />
mon-from2 <br /><br />
mon-to1 <br /><br />
mon-to2 <br /><br />
tue-from1 <br /><br />
tue-from2 <br /><br />
tue-to1 <br /><br />
tue-to2 <br /><br />
wed-from1 <br /><br />
wed-from2 <br /><br />
wed-to1 <br /><br />
wed-to2 <br /><br />
thu-from1 <br /><br />
thu-from2 <br /><br />
thu-to1 <br /><br />
thu-to2 <br /><br />
fri-from1 <br /><br />
fri-from2 <br /><br />
fri-to1 <br /><br />
fri-to2 <br /><br />
sat-from1 <br /><br />
sat-from2 <br /><br />
sat-to1 <br /><br />
sat-to2 <br /><br />
sun-from1 <br /><br />
sun-from2 <br /><br />
sun-to1 <br /><br />
sun-to2 <br />
| 06:00 <br />
| Angabe von Schaltzeiten im Format HH:MM<br />
|}<br />
<br />
== Hinweise zum Betrieb mit FHEM ==<br />
Vor dem Einsatz muss der FHT80b mit der Zentrale (z.B. CUL, FHZ1X00) gepairt werden. Unterbleibt dies, werden nach einer Definition in FHEM zwar Daten vom FHT80b empfangen (z.&nbsp;B. Raumtemperatur), aber es können keine Befehle gesendet werden. Zum Pairen den FHT80b in der Sonderfunktion "cENT" auf "n/a" stellen und danach einen beliebigen Befehl an ihn senden. Wenn ca. zwei Minuten später Sonderfunktion cENT auf "ON" steht, war das Pairing erfolgreich. <br />
<br />
Weitere Hinweise: [[FHT mit RFR CUL pairen]]<br />
<br />
Außerdem muss für das FHT manuell oder per Autocreate ein Device in FHEM angelegt werden. Der Raumcode als Adresse des FHT wird von der FHEM Autocreate-Funktion hexadezimal dargestellt, im Gerät jedoch dezimal. Daher muss die Adresse byteweise umgerechnet werden. Beispiel: FHEM habe ein FHT mit der Adresse 162c angelegt. Dies entspricht dann<br />
hex 16 = 22 dez<br />
hex 2c = 44 dez<br />
dem FHT-Raumcode von 2244.<br />
Beim manuelle Anlegen muss der dezimale Raumcode des FHT umgekehrt byteweise in die hexadezimale FHT-Adresse umgerechnet werden.<br />
<br />
Der FHT80b akzeptiert Befehle von einer Zentrale nur alle 115+x Sekunden (x&nbsp;=&nbsp;0.5*letztes Byte des [[Was ist der Hauscode%3F|FHT-Hauscodes]] (auch ''FHT-ID'' genannt), Beispiel: FHT-ID 1234, Sendeintervall = 115+0,5*4 = 117 Sekunden)<br />
Praktisch ergeben sich so ca. zwei Minuten.<br />
Wenn man also mit FHEM z.B. desired-temp-Wechsel an fünf verschiedene FHT80b sendet, wird es selbst unter optimalen Bedingungen 9-10 Minuten dauern, bis der letzte ausgeführt wird. <br />
<br />
Dies muss insbesondere beim Debuggen von Automationszenarien berücksichtigt werden. Nicht absetzbare Kommandos werden im einem Puffer der FHZ1x00/CUL/CUN gespeichert, obwohl sie im FHEM-Log als abgesetzt erscheinen. Bei größeren Installationen kann dieser Puffer überlaufen ([[EOB]] Fehlermeldung im FHEM Log). Die Puffer sind unterschiedlich groß. Am kleinsten ist er bei den FHZ1x00 mit ca. 40 Byte, was für ca. acht FHT Befehle reicht. Am größten ist er im CULv3 oder CUN mit 200 Bytes, das reicht für ca. 40 Befehle.<br />
<br />
Bei zu kleinem Puffer bietet FHEM die Möglichkeit, einen Softpuffer (fhtsoftbuffer) zu konfigurieren (dieser wirkt jedoch nur bei FHZ1X00PC Zentralen). Insgesamt ist fhtsoftbuffer nur dann sinnvoll einsetzbar, wenn die Funklage an sich gut ist und der Puffer zügig abgearbeitet wird. Softbuffer sollte '''nicht''' eingesetzt werden, wenn die Übertragung der FHT-Befehle gestört ist, da sich dann schnell sehr lange Befehlsketten im Puffer aufbauen können, deren Abarbeitung sehr viel Zeit in Anspruch nehmen kann. Dies kann dazu führen, dass Kommandos an FHTs erst Stunden später ausgeführt werden.<br />
<br />
Um mehr Befehle an ein FHT80b senden zu können, können bis zu 8 Befehle zusammengefasst werden, diese belegen dann nur einen "Zeitslot"<br />
<br />
Beispiele:<br />
:<code>set heizung_wohn desired-temp 20.5 day-temp 19.0 night-temp 16.0</code><br />
<br />
:<code>set hzg_WC mon-from1 07:00 mon-to1 10:00 mon-from2 14:00 mon-to2 23:00</code><br />
<br />
Die Kommunikation des FHT80b mit den Stellantrieben und dem Türkontakt erfolgt ebenso in Zeitabständen von ca. zwei Minuten. In den Pausen sind die Sender und Empfänger von FHT80b und FHT8v abgeschaltet, um Batteriestrom zu sparen.<br />
<br />
Der FHT80b übermittelt ungefähr alle 15 Minuten aktuelle Temperaturdaten an die Zentrale.<br />
<br />
Die Kommunikation mit der Zentrale ist bidirektional, d.h. die Funkzentrale sendet auch Daten an die FHT80b zurück (insbesondere Acknowledge-Meldungen etc). Dies führt dazu, dass im Zusammenhang mit der Sendzeitbegrenzung die Anzahl der [[Maximal nutzbare Geräte|maximal nutzbaren Geräte]] begrenzt ist. Theoretisch lassen sich bis zu 17, in der Praxis eher nur ca. 10 FHT80b sinnvoll mit einer Zentrale steuern.<br />
<br />
== Verschiedene Betriebsarten mit FHEM ==<br />
Da das FHT80 selbst ein Heizprogramm speichern und daher eigentlich auch autark arbeiten kann, stellt sich die Frage, wie FHT80 am Besten in FHEM integriert werden sollte. Es gibt dazu drei wesentliche Szenarien:<br />
<br />
* das FHT80 heizt nur über seine eigenen Heizprogramme, steht also im Automatik Modus. Diese werden jedoch nicht umständlich am FHT80 selber einprogrammiert sondern über FHEM gesetzt. Auch alle gewünschten Änderungen werden über eine Anpassung der im FHT gespeicherten Programme und Setzen von day-temp und night-temp realisiert. Vorteil: Volle Funktionalität auch ohne FHEM, daher ausfallsicher. Nachteil: Änderungen erzeugen hohe Funklast, da ganze Wochenprogramme übertragen werden müssen. Führt bei mehr als fünf bis sechs FHTs idR. zu [[EOB]] und [[LOVF]] Problemen. Außerdem: Beschränkung auf die FHT80 typisch geringe Zahl von Schaltpunkten (vier pro Tag), mehrstufige Temperaturänderungen sind umständlich. Abhängigkeiten in FHEM (Anwesenheitskontrolle, Bedingungen wie Nutzungserkennung durch Bewegungssensoren etc.) sind schwerer umsetzbar. <br />
<br />
* das FHT80 heizt über seine eigenen Heizprogramme, steht also im Automatik Modus. Zusätzlich sendet FHEM z.B. desired-temp Meldungen und greift so in das Heizprofil ein. Vorteil: Grundfunktionalität auch ohne FHEM, daher ausfallsicher: Das Wochenprogramm des FHT80 wird als Grundprogramm und Fallback genutzt. Zusätzliche Heizpunkte oder höhere/niedrigere Temperaturen werden durch FHEM gesteuert. Geringere Funklast, sofern das Grundprogramm selten geändert wird. Beliebige Schaltpunkte, beliebige Temperaturänderungen leicht einstellbar. Nachteil: Komplex. Das Heizverhalten hängt sowohl vom lokalen Programm im FHT80 ab, als auch von Kommandos die FHEM sendet. Das macht die Steuerung unübersichtlich. Problematisch ist insbesondere, wenn lokale Schaltpunkte kurz vorher gesendete FHEM Kommandos negieren. Dies macht z.B. das Herunterfahren der Heizung bei ungeplanter Abwesenheit schwierig.<br />
<br />
* das FHT80 wird in den manuellen Mode geschaltet und nur über FHEM mittels desired-temp Kommandos gesteuert. Vorteil: Da FHEM volle Kontrolle hat, einfache Umsetzung von Abhängigkeiten (Anwesenheitskontrolle, Bedingungen wie Nutzungserkennung durch Bewegungssensoren etc.). Beliebige Schaltpunkte, beliebige Temperaturänderungen leicht einstellbar. Unkomplex: Temperatur hängt nur vom letzt-gesendeten desired-temp Kommando ab. Nachteil: Bei Ausfall von FHEM wird das FHT80 quasi funktionslos und hält nur die letzte eingestellte Temperatur. Es könnten allerdings im FHT gespeicherte Heizprogramme durch manuelles Umschalten am FHT80 auf den Automatikmodus (Tastendruck) aktiviert werden.<br />
<br />
Da das FHT80 auch per FHEM-Befehl zwischen manuellem und automatischem Modus umgestellt werden kann, sind auch Mischformen speziell zwischen den letzten beiden Varianten einsetzbar. Dies wird z.B. im Code Snippet [[FHT80b Automatik setzen]] genutzt.<br />
<br />
== Log-Auszug ==<br />
FHT80b sendet ca. alle zwei Minuten Steuerbefehle an ggf. angeschlossene Ventilstellantriebe. Der einzustellende Wert liegt zwischen 0% und 100% und wird von FHT80b auf Basis der am Gerät eingestellten Solltemperatur und der vom Gerät gemessenen Ist-Temperatur berechnet:<br />
<br />
FHT &lt;device-name&gt; actuator: 0%<br />
<br />
Außerdem sendet FHT80b ca. 4 mal pro Stunde folgenden Statusbericht:<br />
<br />
FHT &lt;device-name&gt; actuator: 0%<br />
FHT &lt;device-name&gt; measured-temp: 23.1 (Celsius)<br />
FHT &lt;device-name&gt; battery: ok<br />
FHT &lt;device-name&gt; lowtemp: ok<br />
FHT &lt;device-name&gt; window: closed<br />
FHT &lt;device-name&gt; windowsensor: ok<br />
FHT &lt;device-name&gt; warnings: none<br />
<br />
Die dazu nötige bidirektionale Kommunikation kann mit FHEM <br />
mitprotokolliert werden ("set CUL raw X61" vorher nicht vergessen). Hier ein <br />
beispielhafter Mitschnitt: <br />
<br />
2008-09-28 13:04:18 FHT wz actuator: 0% <br />
2008-09-28 13:04:18 FHT wz actuator: 0% <br />
2008-09-28 13:04:18 FHT wz start-xmit: 17 <br />
2008-09-28 13:04:18 FHT wz FHZ:start-xmit: 17 <br />
2008-09-28 13:04:19 FHT wz measured-low: 21.9 (Celsius) <br />
2008-09-28 13:04:19 FHT wz FHZ:measured-low: 21.9 (Celsius) <br />
2008-09-28 13:04:19 FHT wz measured-high: 0 <br />
2008-09-28 13:04:19 FHT wz FHZ:measured-high: 0 <br />
2008-09-28 13:04:19 FHT wz ack: 0 <br />
2008-09-28 13:04:20 FHT wz FHZ:ack: 0 <br />
2008-09-28 13:04:20 FHT wz warnings: none <br />
2008-09-28 13:04:20 FHT wz FHZ:warnings: none <br />
2008-09-28 13:04:20 FHT wz ack: 0 <br />
2008-09-28 13:04:20 FHT wz FHZ:ack: 0 <br />
2008-09-28 13:04:20 FHT wz end-xmit: 0 <br />
2008-09-28 13:04:20 FHT wz FHZ:end-xmit: 0<br />
<br />
Jede Zeile steht für ein Telegramm (und nicht für 3, wie beim FS20). <br />
<br />
FHZ:xxx Telegramme wurden von der FHZ (oder CUN/CUL) gesendet, die anderen vom FHT. <br />
<br />
FHEM fasst measured-low und measured-high zu measured-temp zusammen, es werden also im normalen log (telnet: inform timer) zwei Zeilen weniger gemeldet. <br />
<br />
17 ist der Hauscode der protokollierten FHZ. Wenn die FHZ nicht mit dem richtigen Hauscode antwortet, dann geht die Kommunikation nicht weiter. <br />
<br />
Wenn das FHT nicht an der FHZ angemeldet ist (d.h., das FHT hat nicht den Hauscode des FHZ gespeichert), werden keine Temperaturdaten übermittelt. Set Prog:Cent:N/A setzt den FHT Hauscode auf 100, dann sollte jede FHZ auf "start-xmit" antworten, und das FHT merkt den ersten. Noch besser ist es, dem FHT via FHEM etwas zu senden, dann muss nicht auf die nächste Temperaturmeldung (bis zu 15 Minuten) gewartet werden. <br />
<br />
Falls die Gegenseite nicht wie erwartet antwortet, wird nach einem Timeout das Telegramm einmal wiederholt. Falls immer noch keine korrekte Antwort vorliegt, wird nach 115+x Sekunden der ganze Vorgang einmal wiederholt. <br />
<br />
Durch diese recht umfangreiche Kommunikation entsteht im Zusammenhang mit der Sendezeitbeschränkung die maximale Anzahl nutzbarer Geräte von ca. einem Dutzend.<br />
<br />
== Bekannte Probleme ==<br />
* Es gibt zwei weitere, gleich aussehende Geräte mit geringerem Funktionsumfang. Der [[FHT8b]] hat keine Verbindung zu Fensterkontakten. Der [[FHT8]] hat keinen bidirektionalen Funk und kann nicht mit einer Zentrale/FHEM verbunden werden.<br />
* Die Sendefrequenzen einiger FHT80b sind nicht besonders genau auf den eigentlichen Wert von 868,35 MHz justiert und streuen bei verschiedenen Geräten. Die FHZ 1x00PC Geräte sind gegenüber leichten Abweichungen der Frequenz durch eine etwas höhere Empfangsbandbreite eher unempfindlich. Die [[CUL]] oder [[CUNO]] halten die eingestellte Frequenz dagegen trennschärfer ein, sodass es zu Empfangsproblemen kommen kann. Können Signale eines FHT nicht empfangen werden, kann es sinnvoll sein, probeweise die Frequenz des CUL zu ändern (in 0,05 MHz Schritten), oder die Bandbreite aufzuweiten, z.B. auf 464 kHz.<br />
* In seltenen Fällen fehlerhafte Aktuator Meldungen, siehe [[Lime-Protection Bug]] <br />
* FHTs hören in der Regel nach 5-10 Tagen auf, von sich aus Daten zur Zentrale zu senden, wenn sonst keine Kommunikation mit dem FHT stattfindet. Ein regelmäßiges z.B. wöchentliches Stellen der Uhrzeit oder wöchentliches Abfragen der wichtigsten Parameter (report2 = 255) vorteilhaft zu eher "funklastarmen" Zeiten schafft Abhilfe; z.B.:<br><code>define fht_reportZimmer1 at *04:00:00 {if ($wday == 1) { fhem("set hzg_Zimmer1 report2 255") } }</code><br />
* Die o.g. Situation bringt häufig auch die Actuator-Meldung "'''unknown_69'''" mit sich. Eine Beschreibung zur Behebung findet sich in {{Link2Forum|Topic=6755|Message=28860|LinkText=diesem Forums-Post}}.<br />
* Der Betrieb von FHTs mit einen [[RFR CUL]] kann zu besonderen Problemen führen, siehe [[RFR CUL und FHT80]]<br />
* Es kann vorkommen, dass ein oder auch alle FHT plötzlich aufhören Temperatur und andere Werte zu senden (aber zB actuator und current_action weiter senden). Meist nehmen sie dann auch keine Befehle vom fhem aus an. Das kann dann an einem '''Verbindungsproblem zur Zentrale'''/fhem liegen (Ursache unklar). Eine Lösung ist aber im jeweiligen FHT in den Sondereinstellungen die Zentrale zu deaktivieren und wieder einzustellen (Prog - Sond - CEnt - na, Prog - Sond - CEnt - on). Vgl. [[Funk-Heizkörperregler_Kurz-Bedienungsanleitung_FHT|FHT-Anleitung]], {{Link2Forum|Topic= 16422|Message=155804|LinkText=Forum dazu}}<br />
<br />
== Links ==<br />
* [[Funk-Heizkörperregler_Kurz-Bedienungsanleitung_FHT|Kurz-Bedienungsanleitung]]<br />
* Anleitung [http://www.eq-3.de/Downloads/eq3/downloads_produktkatalog/andere_produkte_bda/FHT80B_UM_G_080812.pdf hier (eQ-3)] oder {{DocLink|elv|/Assets/Produkte/8/856/85643/Downloads/85643_FHT80B_UM.pdf hier (ELV)}} als PDF<br />
* Baugleich auch als Set ('''FHT80b''', [[FHT80TF]]) von Medion (bei Aldi oder ebay): [http://www.discounter-archiv.de/de/archiv/ALDI-Nord/2011-01-06/Automatische-Funk-Heizkoerpersteuerung/692135/ Lifetec MD12050]<br />
* [[Kommunikationsprobleme mit FHT]] <br />
* [[Was ist der Hauscode?]]<br />
<br />
Eine Reihe von Code Snippets zum Thema FHT80b:<br />
* [[FHT80b Einstellungen]]<br />
* [[FHT80b Automatik setzen]]<br />
* [[FHT: Datum und Zeit von FHEM setzen lassen]] <br />
<br />
[[Kategorie:FHT Components]]<br />
[[Kategorie:Heizungssteuerung]]<br />
[[Kategorie:868MHz]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Raspberry_Pi_und_1-Wire&diff=28685Raspberry Pi und 1-Wire2018-12-16T09:50:49Z<p>Fabian: Absatz zum GPIO4-Modul ins Kapitel Busmaster verschoben</p>
<hr />
<div>Der [[:Kategorie:Raspberry Pi|Raspberry Pi]], abgekürzt RPi ist ein Einplatinencomputer der [http://www.raspberrypi.org/ Raspberry Pi Foundation], der unter Linux läuft und über eine Vielzahl von Anschlüssen verfügt.<br />
<br />
FHEM läuft auf allen Modell des Raspberry Pi. Während [[:Kategorie:Raspberry Pi|hier]] die Installation von FHEM beschrieben wird, soll sich diese Seite nur mit dem Anschluss von 1-Wire Devices an den RPi befassen.<br />
<br />
== Hardware ==<br />
Bereits von der Hardware her bietet der RPi verschiedene Möglichkeiten zum Anschluss von 1-Wire-Devices<br />
<br />
=== USB-Port ===<br />
Über einen der USB-Ports des RPi mit entsprechendem Adapter. Hierbei sollte, wenn es sich nicht nur um wenige 1-Wire-Devices handelt, ein USB-Hub mit eigener Stromversorgung zwischengeschaltet werden. Mit USB-Extendern lässt sich dies bequem auch bis zu 20m entfernt vom RPi bewerkstelligen.<br />
<br />
Alle bekannten USB/1-Wire Adapter arbeiten mit dem RPi. Allerdings ist es möglicherweise (nur, wenn Fehler auftreten&#160;!) nötig, dafür ein Kernel-Update durchzuführen, da in manchen älteren Versionen des Linux-Kernels für den RPi Fehler im USB-Stack enthalten sind.<br />
<br />
=== COC-Modul ===<br />
Anschluss über ein COC-Modul des Herstellers [http://busware.de busware.de]. Siehe hierzu im Detail [[COC und 1-wire]]].<br />
<br />
=== RPI2-Modul ===<br />
Anschluss über ein RPI2-Modul des Herstellers [http://www.sheepwalkelectronics.co.uk/product_info.php?products_id=30 Sheepwalk Electronics]. Dieses Modul wird direkt auf den internen I2C-Bus des RPi aufgesteckt. Im Kaufzustand bietet es für den 1-Wire-Bus sowohl eine RJ45-Buchse, als auch einen Schraubklemmenanschluss. Diese sind leider beide so hoch, dass das Modul nicht mehr in das RPi-Gehäuse passt. Hier kann aber leicht abgeholfen werden (to be continued).<br />
<br />
Zur Ansteuerung ist auf dem RPi zunächst das Starten zweier Kernelmodule nötig, dazu als root ausführen<br />
<br />
<nowiki>modprobe i2c-bcm2708<br />
modprobe i2c-dev</nowiki><br />
Der automatische Start dieser beiden Module kann in der Datei /etc/modules eingetragen werden. <br />
<br />
Zudem muss beim aktuellen Raspian noch die Datei /boot/config.txt angepasst werden:<br />
<nowiki>dtparam=i2c_arm=on</nowiki><br />
<br />
Die oben genannten Schritte können auch über (sudo) raspi-config durchgeführt werden. Damit wird sichergestellt, dass die für die jeweilige Kernelversion notwendigen Schritte durchgeführt werden ('8 Advanced Options' -> 'A7 I2C').<br />
<br />
Bei Vorhandensein des Paketes i2c-tools wird dann die korrekte Erkennung des Adapters mit dem Befehl<br />
<br />
<nowiki>i2cdetect -y 1</nowiki><br />
überprüft, der 1-Wire-Busmaster DS2482-100 sollte als I2C-Device mit der ID 0x18 gefunden werden.<br />
<br />
=== GPIO4-Port ===<br />
1-wire-Komponenten können direkt an den GPIO-Port des RPi angeschlossen und in FHEM konfiguriert werden.<br />
<br />
==== Software-Installation ====<br />
Die Software-Installation des GPIO im RPi erfolgt je nach Kernelversion unterschiedlich:<br />
<br />
===== vor 2015 bzw. Kernelversion 3.18.3 =====<br />
Zur Ansteuerung ist auf dem RPi zunächst das Starten zweier Kernelmodule nötig, dazu als root ausführen<br />
<br />
<nowiki>modprobe w1-gpio pullup=1</nowiki><br />
<nowiki>modprobe w1-therm</nowiki><br />
<br />
Waren die Schritte erfolgreich, gibt es jetzt im Verzeichnis ''/sys/bus/w1/devices/'' für jeden Sensor ein Unterverzeichnis mit seiner Kennung, z.B. ''28-000004e147d6''. Die dort stehende Datei ''w1_slave'' enthält das Ergebnis der Datenübertragung vom Sensor. Um die Module dauerhaft zu laden, sind sie noch in die Datei ''/etc/modules'' einzutragen:<br />
<br />
<nowiki><br />
# /etc/modules<br />
w1-gpio pullup=1<br />
w1-therm </nowiki><br />
<br />
<br />
===== ab 2015 bzw. Kernelversion 3.18.3 =====<br />
Da sich mit Kernelversion 3.18.3 die Handhabung der Module geändert hat (vgl. [[#1-wire am GPIO4-Port funktioniert nicht mehr nach Systemupdate]] - die Datei <code>/etc/modules</code> wird im Prinzip garnicht mehr benötigt (Details s. [[#Links]]). Somit ist hier eine andere (einfachere) Konfiguration nötig:<br />
* Am besten erst einmal ein ordentliches System-Update durchführen:<br />
<pre><br />
sudo apt-get update<br />
sudo apt-get dist-upgrade -f<br />
sudo rpi-update<br />
sudo reboot<br />
</pre><br />
* Kernelversion kontrollieren (muss jetzt mind. v3.18.3 sein):<br />
<pre><br />
uname -r<br />
</pre><br />
* Dann fügt man den folgende Zeile in <code>/boot/config.txt</code> ein:<br />
<pre><br />
# activating 1-wire with pullup<br />
dtoverlay=w1-gpio-pullup<br />
</pre><br />
* Und startet das System neu<br />
<pre><br />
sudo reboot<br />
</pre><br />
<br />
Zusätzlich kann man gleich eine '''Debugging-Funktion''' aktivieren:<br />
* Dazu fügt man den folgende Zeile in <code>/boot/config.txt</code> ein:<br />
<pre><br />
# activating device tree debugging (use: sudo vcdbg log msg)<br />
dtdebug=on<br />
</pre><br />
* Abrufen kann man die Debug-Informationen dann mit:<br />
<pre><br />
sudo vcdbg log msg<br />
</pre><br />
<br />
==== Elektrische Installation ====<br />
Eine gute Einführung zum Thema geben die Links von RaspiProjekt.de (s. [[#Links]]).<br />
<br />
Dazu wird im ersten Schritt der 1-Wire Bus (bzw. zum Test nur ein einzelner Sensor) mit dem GPIO-Port des RPi verbunden, und zwar<br />
*1-Wire GND an GND vom Pi (Pin 6)<br />
*1-Wire Datenleitung an GPIO04 (Pin 7)<br />
*1-Wire VDD an +3,3V vom Pi (Pin 1)<br />
*Ausserdem ist noch ein Pullup-Widerstand von z.B. 4,7kOhm zwischen Pin1 und Pin7 zu schalten.<br />
<br />
Obwohl die nominale Spannung für 1-Wire Devices 5V beträgt, ist hier die verringerte Spannung nötig, weil die GPIO-Ports des RPi nur 3,3, V vertragen und durch höhere Spannungen zerstört werden. Als Alternative kann man den 1-Wire Bus auch 5V (Pin 2) anschließen, dann '''muss''' aber zwingend das Signal der 1-Wire Datenleitung durch einen Spannungsteiler (z.B. 10 kOhm und 6.8 kOhm) auf 3,3 V begrenzt werden. Besser man verwendet einen aktiven Pegelwandler der sich mit einem einfachen MOS-FET realisieren lässt : [[1-Wire Pegelwandler]]<br />
<br />
==== Konfiguration von 1-wire-Komponenten am GPIO ====<br />
Im Folgenden sind für verschiedene 1-wire-Komponenten die grundlegenden fhem-Konfigurationen beschrieben.<br />
<br />
===== Konfiguration des Busmasters =====<br />
Um den 1-Wire Bus in FHEM einzubinden, muss noch das '''Modul 58_GPIO4.pm aus dem Verzeichnis ''/opt/fhem/contrib'' in das Hauptverzeichnis ''/opt/fhem/FHEM/'' kopiert werden''' und mit <br />
:<code>define RPi GPIO4 BUSMASTER</code><br />
bekannt gemacht werden. Nach einem Neustart von FHEM werden die Sensoren automatisch erkannt (FHEM-Forum-Beitrag {{Link2Forum|Topic=10431}}).<br />
<br />
Das beschriebene Kernelmodul unterstützt momentan die IDs 10- (DS1820 u. DS18S20) sowie 28- (DS18B20). Im "Auslieferungszustand" können maximal 10 Sensoren angeschlossen werden. <br />
Unter [http://www.raspiprojekt.de/anleitungen/schaltungen/9-1wire-mit-temperatursensor-ds18b20.html?showall=&start=4] ist beschrieben, wie man die Anzahl erhöhen kann. Anschließend ist nur noch ein Neustart des RPi nötig.<br />
<br />
===== Temperatursensor DS18B20 =====<br />
Ist der Temperatursensor richtig elektrisch installiert (vgl. [[#Links]] von RaspiProjekt.de), so wird automatisch ein eigenes Verzeichnis mit der ID des Sensors im 1-wire-Pfad des RPi angelegt:<br />
<pre><br />
# 1-wire-Pfad des RPi:<br />
/sys/bus/w1/devices/<br />
<br />
# Bsp.:<br />
$ ls /sys/bus/w1/devices/<br />
28-001451df14ff # ID des Temperatursensors <br />
w1_bus_master1 # Standardeintrag des 1-wire-Bus<br />
</pre><br />
Am besten schliesst man mehrere Sensoren nacheinander an, damit man die ID dem richtigen Sensor zuordnen kann.<br />
<br />
Mit der ID wird der Sensor jetzt im FHEM konfiguriert:<br />
<pre><br />
define EG_Balkon GPIO4 28-001451df14ff<br />
attr EG_Balkon model DS18B20<br />
attr EG_Balkon room GPIO-Devices<br />
attr EG_Balkon group 1-wire<br />
<br />
define FileLog_EG_Balkon FileLog ./log/EG_Balkon-%Y-%W.log EG_Balkon<br />
attr FileLog_EG_Balkon logtype text<br />
</pre><br />
<br />
Den zugehörigen Plot erstellt man am einfachsten über die WebGUI des FHEM:<br />
* ggf. FHEM neu starten (falls die Komponente und der FileLog nicht auftauchen)<br />
* FileLog aufrufen<br />
* "Create SVG Plot" auswählen<br />
* ggf. Einstellungen anpassen (geht auch im Nachhinein)<br />
* "Write .gplot file" auswählen<br />
* weiter unten <code>attr SVG_FileLog_EG_Balkon room Balkon</code> eingeben<br />
<br />
=== UART-Schnittstelle ===<br />
Der RPi verfügt auch über eine UART-Schnittstelle, an diese kann direkt ein Serielles 1-Wire Interface angeschlossen werden (IN VORBEREITUNG)<br />
{{Hinweis|Die Vorbereitung der UART-Schnittstelle ist in [[Raspberry Pi]] beschrieben. An dieser Stelle sollten auch zukünftig nur Besonderheiten und Abweichungen stehen!}}<br />
<br />
== Software ==<br />
Die Ansteuerung des 1-Wire Bus auf dem RPi kann durch unterschiedliche Software-Systeme erfolgen. Verbreitet mit FHEM sind<br />
<br />
* '''OWX''' sowie die zugehörigen Frontendmodule OWAD, [[OWCOUNT]], OWID, OWLCD, OWMULTI, OWSWITCH und OWTHERM. Das '''OWX'''-Modul operiert direkt auf der jeweiligen Hardware (USB bzw. Seriell) oder liest die Daten über Netzwerk (COC/CUNO/Arduino) und reicht sie an spezialisierte Frontendmodule weiter.<br />
* '''OWServer''', ein Modul, welches die vorhergehende Installation des Softwarepaketes [http://www.owfs.org OWFS] erfordert. OWFS startet einen speziellen Server, der die Kommunikation mit der Hardware übernimmt und die Daten dann an '''OWServer''' weiterleitet. Die Installtion bzw Kompilierung vom OWServer auf dem Rasperry ist unter [[OWServer & OWDevice#owfs Pakete installieren|owfs Pakete installieren]] beschrieben. Zu OWServer passt ein generisches Frontendmodul OWDevice, siehe [[OWServer & OWDevice]].<br />
<br />
Nachfolgend ist die Kompatibilität dieser Softwaresysteme mit den einzelnen Hardware-Möglichkeiten aufgeführt.<br />
<br />
{| class="wikitable" <br />
! Anschluss <br />
! Gerät <br />
! Unterstützte 1-Wire Devices <br />
! Besonderheit <br />
! Stromversorgung 1-Wire Bus<br />
|- <br />
| Direkt an USB <br />
| DS9490 Adapter <br />
| <br />
| <b>funktioniert</b> (DS9490R) auf dem Raspi mit OWServer ({{Link2Forum|Topic=59900}})<br />
<b>funktioniert nicht</b> mit OWX, weil der enthaltene Chip DS2490 derzeit nur über <br /><i>libusb</i> ansteuerbar ist. Abhilfe ist in Arbeit. <br />
| &#160;??<br />
|- <br />
| Direkt an USB <br />
| USB9097 Adapter<br />
| rowspan="8" | Alle von OWX unterstützten Devices, d.h. <br /><p>DS18x20, DS1822 Temperatursensor <br /> DS2406, DS2408, DS2413 Schalter <br /> DS2423 Zähler <br />DS2438 Multisensor <br /> DS2450 4 Kanal ADC <br />LCD-Controller von [http://www.fuchs-shop.com/de/shop/6/1/13372316/ Louis Swart]<br />Alle anderen 1-Wire Devices: Nur ID<br />
</p><br />
| <b>funktioniert</b> auf der FB7390, das Kernelmodul <i>ch341.ko</i> findet man [https://sites.google.com/site/fhemarduino/file-cabinet/ch341.ko?attredirects=0&amp;d=1 hier]<br />
| Ja, 5V<br />
|- <br />
| Direkt an USB <br />
| Eigenbau, <br /> mit FT232RL und DS2480 Bus-Master <br />
| <b>funktioniert</b>, Fertiggeräte eventuell bei EBay erhältlich, <br />siehe auch [[Interfaces für 1-Wire]]<br />
| Ja, 5V<br />
|- <br />
| Direkt an USB <br />
| LinkUSBi Adapter <br />
| <b>funktioniert</b>, verwendet das FTDI Kernelmodul.<br />Achtung: Es kann zu Timing-Problemem kommen. <br /> Erhältlich z.B. [http://www.fuchs-shop.com/de/shop/17/1/13372210/ hier]<br />
| Ja, 5V an Pin2 (limited to 50mA)<br />
|- <br />
| Über USB-zu-Seriell-Konverter <br /> 9- oder 25-polig <br /> mit Winchiphead CH341-Chip<br />
| Konverter + DS9097U-(009/S09, E25) <br />
| <b>funktioniert</b> auf der FB7390, das Kernelmodul <i>ch341.ko</i> findet man [https://sites.google.com/site/fhemarduino/file-cabinet/ch341.ko?attredirects=0&amp;d=1 hier]<br />
| Nur bei den 25-poligen Modellen als Standard,<br /> bei den 9-poligen Modellen<br /> externe Versorgung oder Modifikation des DS9097 nötig<br />
|- <br />
| Über USB-zu-Seriell-Konverter <br /> 9- oder 25-polig <br /> mit Prolific PL2303-Chip<br />
| Konverter + DS9097U-(009/S09, E25) <br />
| <b>funktioniert</b> auf der FB7390, das Kernelmodul <i>pl2303.ko</i> findet man [https://groups.google.com/group/fhem-users/attach/1c0530caa5d8a864/pl2303.ko?part=2&amp;authuser=0 hier]<br />
| Nur bei den 25-poligen Modellen als Standard,<br /> bei den 9-poligen Modellen<br /> externe Versorgung oder Modifikation des DS9097 nötig<br />
|- <br />
| Über USB-zu-Seriell-Konverter <br /> 9- oder 25-polig <br /> mit FTDI RL232-Chip<br />
| Konverter + DS9097U-(009/S09, E25) <br />
| <b>funktioniert</b> auf der FB7390, das Kernelmodul <i>ftdi_sio.ko</i> ist auf der <br /> FritzBox vorhanden <br />
| Nur bei den 25-poligen Modellen als Standard,<br /> bei den 9-poligen Modellen<br /> externe Versorgung oder Modifikation des DS9097 nötig<br />
|- <br />
| Direct an USB<br />
| Arduino mit USB-Anschluss (UNO, Mega, Nano...)<br />
| rowspan="2"| 1-Wire Bus direkt am Arduino (reine Softwarelösung) oder (stabiler im Betrieb) in Verbindung mit DS2482-Busmaster (am I2C des Arduinos). Mit DS2482-100 ist 1 1-Wire-Bus (optional mit Strong-pullup über externen MosFET), mit DS2482-800 sind 8 busse (nur mit internem Strong-pullup) an 1 Arduino gleichzeitig möglich.<br />
| rowspan="2"| Ja, 3,3V oder 5V je nach Arduino-modell.<br />
|-<br />
| Über Netzwerk<br />
| Arduino mit Ethernetshield, Arduino mit ENC28J60-shield, Arduino Ethernet <br />
|-<br />
| Über Netzwerk und CUNO<br />
| CUNO <br />
| Mit OWX: Alle von OWX unterstützten Devices <br /> Ohne OWX: Nur DS18x20, DS1822 Temperatursensor <br />
| <b>funktioniert</b> mit gewissen Einschränkungen, siehe [[CUNO und 1-wire]]<br />
| Ja, aber nur 3,3 V. <br /> Kann allerdings zu 5V modifiziert werden<br />
|- <br />
| Über Netzwerk und <br /> Ethersex-Gerät<br />
| AVR-Net-IO oder ähnliches <br />
| DS18x20, DS1822 Temperatursensor <br /> DS2502 EEPROM <br />DS2450 4 Kanal ADC <br />
| <b>funktioniert</b>, siehe [[FHEM und 1-Wire]]und [[AVR-NET-IO]]<br /><br />
| &#160;??<br />
|}<br />
<br />
== Problembehebung ==<br />
=== 1-wire am GPIO4-Port funktioniert nicht mehr nach Systemupdate ===<br />
'''Problem'''<br />
<br />
Es kann passieren, dass nach einem Systemupdate (apt-get update oder apt-get dist-upgrade) die 1-wire-Geräte am GPIO4-Port plötzlich nicht mehr funktionieren. Dies hat dann aller Wahrscheinlichkeit die Ursache, dass ein Kernel-Upgrade von "vor 3.18.3" auf "danach" gemacht wurde. Mit Kernelversion 3.18.3 ist die Handhabung der Kernelmodule umgestellt worden (vgl. auch [[#GPIO4-Port]]):<br />
* vor v3.18.3: hier wurden Module in die /etc/modules eingetragen. Dieses Vorgehen ist fast überall beschrieben.<br />
* ab v3.18.3: jetzt wurde das sog. Device-Tree-Verfahren eingeführt, das anders arbeitet - und erst einmal die alte Konfiguration blockiert (!). (Details s. unter [[#Links]])<br />
Auch ein Aufruf von <code>sudo rpi-update</code> hilft allein nicht weiter (ist aber immer sinnvoll).<br />
<br />
'''Lösung'''<br />
<br />
Die "korrekte" Lösung wäre die Umstellung auf Device-Tree-Konfiguration: <br />
* Dazu fügt man den folgende Zeile in <code>/boot/config.txt</code> ein:<br />
<pre><br />
# activating 1-wire with pullup<br />
dtoverlay=w1-gpio-pullup<br />
</pre><br />
* Entfernt die Module <code>w1-gpio</code> und <code>w1-therm</code> aus das <code>/etc/modules</code> (oder kommentiert sie aus)<br />
* Und startet das System neu<br />
<br />
Zusätzlich kann man gleich eine '''Debugging-Funktion''' aktivieren:<br />
* Dazu fügt man den folgende Zeile in <code>/boot/config.txt</code> ein:<br />
<pre><br />
# activating device tree debugging (use: sudo vcdbg log msg)<br />
dtdebug=on<br />
</pre><br />
* Abrufen kann man die Debug-Informationen dann mit:<br />
<pre><br />
sudo vcdbg log msg<br />
</pre><br />
<br />
'''Alternativer Workaround'''<br />
<br />
Alternativ zur "korrekten" Lösung kann man die Device-Tree-Funktionalität auch einfach deaktivieren - dann bleibt alles wie bisher.<br />
<br />
* Dazu fügt man den folgende Zeile in <code>/boot/config.txt</code> ein:<br />
<pre><br />
# disabling device tree functionality:<br />
device_tree=<br />
</pre><br />
* Und startet das System neu.<br />
<br />
== Links ==<br />
Zu GPIO:<br />
* [http://neubert-volmar.de/Hausautomation/RaspberryPi/index.html Beispiel zur Nutzung von 1-wire am GPIO-Port & eines Eigenbau-Adapters]<br />
* [https://raspiprojekt.de/anleitungen/hardware/147-gpio-grundlagen.html RaspiProjekt.de - GPIO-Grundlagen]<br />
* [http://www.raspberrypi.org/documentation/usage/gpio/ RaspberryPi.org - GPIO-Grundlagen]<br />
* [http://pi.gadgetoid.com/pinout/pin7_gpio4 Pin-Belegungen des Raspi]<br />
* [https://www.raspiprojekt.de/anleitungen/schaltungen/9-1wire-mit-temperatursensor-ds18b20.html RaspiProjekt.de - Anbindung von Temperatursensoren]<br />
<br />
Zu Device-Tree:<br />
* [https://www.raspiprojekt.de/21-blog/153-neuer-kernel-neues-glueck.html RaspiProjekt.de - Neuer Kernel neues Glück]<br />
* [http://www.raspberrypi.org/documentation/configuration/device-tree.md RaspberryPi.org - Device Trees, Overlays and Parameters]<br />
* [https://raspiprojekt.de/anleitungen/hardware/154-geraetetreiber-und-device-tree.html RaspiProjekt.de - Gerätetreiber und Device Tree]<br />
* [https://github.com/raspberrypi/linux/tree/rpi-3.18.y/arch/arm/boot/dts Liste aller verfügbaren Device-Tree Module]<br />
<br />
[[Kategorie:Raspberry Pi]]<br />
[[Kategorie:1-Wire]]<br />
[[Kategorie:Interfaces]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=27620DbLog2018-08-07T13:43:39Z<p>Fabian: Kapitel "Performance-Optimierung" erstellt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])<br />
}}<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen in FHEM recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als {{Link2CmdRef|Lang=de|Anker=FileLog|Label=FileLog}} gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann FHEM die Log-Daten mittels {{Link2CmdRef|Lang=de|Anker=DbLog|Label=DbLog}} in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
;Hinweis:<br />
Reporting und Management von DbLog-Datenbankinhalten kann mit dem Modul [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] stattfinden.<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
Es wird empfohlen diese Datei zu kopieren und erst dann entsprechend zu bearbeiten. Am Besten kopiert man diese Datei in das FHEM Home Directory /opt/fhem/ und achtet auf die entsprechenden Rechte!<br />
chown fhem:dialout /opt/fhem/db.conf<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
Unbedingt beachten: bei Verwendung des Moduls configdb wird die Konfigurationsdatei aus der '''''Datenbank''''' gelesen. Deshalb ist es erforderlich, das File mittels <code>configdb fileimport db.conf </code> vorher zu importieren !<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es mehrere Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
* Ausschluß von Device/Reading-Kombinationen über das Attribut "excludeDevs". Es können [https://fhem.de/commandref_DE.html#devspec devspec] verwendet werden. <br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. {{Link2CmdRef|Lang=de|Anker=event-on-update-reading}})<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe {{Link2CmdRef}}.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
Die Datenbank ist relativ simpel gestaltet und besteht lediglich aus den folgenden beiden Tabellen:<br />
* current<br />
* history<br />
<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
==== current ====<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Um doppelte Einträge in der Tabelle zu vermeiden, wurden die Möglichkeit geschaffen Primary Keys zu definieren. Da in der Spalte <code>READING</code> u.U. bei verschiedenen Geräten gleiche Namen vorkommen können, sollte der Primary Key um den Gerätenamen erweitert werden. Der Primary Key sollte also aus <code>DEVICE</code> und <code>READING</code> bestehen. Um in der Datenbank ''fhem'' diesen PK zu setzen, kann folgender SQL Code verwendet werden:<br />
<br />
<syntaxhighlight lang="sql"><br />
ALTER TABLE `fhem`.`current` <br />
CHANGE COLUMN `DEVICE` `DEVICE` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
CHANGE COLUMN `READING` `READING` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
ADD PRIMARY KEY (`DEVICE`, `READING`);<br />
</syntaxhighlight><br />
<br />
==== history ====<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen oder Auswertungen mit [https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten DbRep] anzufertigen<br />
<br />
{{Todo|Ausbauen}}<br />
<br />
Um Problem beim Import von cacheFiles zu vermeiden, kann in der Datenbank ein PK angelegt werden, welcher Timestamp, Device und Reading umfasst. Dadurch werden doppelte Einträge wirksam verhindert.<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
Des Weiteren ist zu beachten: <br />
<br />
On-Off-Plots<br />
<br />
EG_Bad:window:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:0/eg<br />
<br />
unter Berücksichtigung von dim-Werten:<br />
<br />
EG_WoZi_Licht:value:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:($1eq"dim"?$2*0.01:0)/eg<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE INDEX Search_Idx ON `history` (DEVICE, READING, TIMESTAMP);<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Anstatt nano kann jeder andere kompatible Editor verwendet werden. Weiterhin bitte beachten, dass die hier genannten Befehle teilweise root-Rechte voraussetzen. Entweder komplett als root arbeiten, oder mittels sudo.<br />
<br />
Unter Ubuntu/debian: <br />
apt-get update && apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
Hinweis: im Folgenden ist "#" der normale Prompt und "mysql>" der prompt innerhalb mysql, dieser kann mit exit verlassen werden. <br />
<br />
Zum Test mal mit mysql verbinden:<br />
# mysql -p -u root<br />
Enter password:<br />
mysql> exit<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann die Datei /opt/fhem/contrib/dblog/db_create_mysql.sql als Vorlage verwendet und das Passwort und der Benutzername geändert werden. <br />
cd /opt/fhem/contrib/dblog/<br />
nano db_create_mysql.sql<br />
Dann wird die Datei eingelesen (root Passwort wird abgefragt): <br />
<br />
# mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
# mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
nano /opt/fhem/db.conf<br />
<br />
Jetzt kann unter FHEM ein DbLog-Device angelegt werden (mit dem beispiel wird alles geloggt: <br />
define logdb DbLog ./db.conf .*:.*<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in FHEM stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich.<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<syntaxhighlight lang="sql"><br />
# mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from history; # Achtung, kann sehr groß werden .... #<br />
</syntaxhighlight><br />
<br />
== Beispiel: Abfragescript PHP/MySQL ==<br />
Um eine schnelle Übersicht zu bekommen habe ich mir dieses Script geschrieben:<br />
<syntaxhighlight lang="php"><?php $pdo = new PDO('mysql:host=localhost;dbname=fhem', 'fhemuser', 'fhempasswort');<br />
echo '<h2>Tabelle Current</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th><th>Readings</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE, GROUP_CONCAT(DISTINCT READING ORDER BY READING DESC SEPARATOR '</li><li>') FROM current GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td><td><ol><li>" . $row[2] . "</li></ol></td></tr>";<br />
}<br />
echo "</table>";<br />
<br />
<br />
echo '<h2>Tabelle History</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE FROM history GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td></tr>";<br />
}<br />
echo "</table>";<br />
?><br />
</syntaxhighlight><br />
<br />
Bitte passt fhemuser und fhempasswort an. Das Ganze kommt dann nach ''/var/www/html/fhemdb.php'' und ist mit ''<IP>/fhemdb.php'' aufrufbar. Wenn ihr den 2. Block für die history Tabelle ausklammert oder entfernt läuft das Script viel schneller ab - klar die history Tabelle ist meist randvoll.<br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_splitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
<br />
Dazu muss der Modulautor in der [[DevelopmentModuleIntro#X_Initialize|Initialize-Funktion]] eine <code>DbLog_splitFn</code> bereitstellen:<br />
<br />
<syntaxhighlight lang="perl"><br />
sub X_Initialize($)<br />
{<br />
my ($hash) = @_;<br />
...<br />
$hash->{DbLog_splitFn} = "X_DbLog_splitFn";<br />
}<br />
</syntaxhighlight><br />
<br />
Die genaue Aufrufsyntax und Funktionweise einer DbLog_split-Funktion findet man [[DevelopmentModuleIntro#X_DbLog_split|hier]].<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in der Datenbank herumzuwühlen (s.u.). Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der {{Link2CmdRef|Lang=de|Anker=DbLog}} und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor FHEM stoppt, um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden, ohne FHEM stoppen zu müssen. <br />
<br />
Datenbanken kann man ohne weitere Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt FHEM stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
FHEM wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
== Datenbank migrieren ==<br />
Eine schöne Anleitung zur Migration von SQLite zu MySQL/MariaDB mit Hilfe von [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] findet sich hier: [https://demaya.de/fhem-umzug-sqlite-mysql-mariadb/].<br />
<br />
Hinweis: Wenn die SQLite-DB sehr groß wird, kann es sein, dass der oben beschriebene Weg nicht funktioniert (konkret war dies bei meiner 15 GB großen DB nicht möglich, der Prozess hat sich immer nach mehreren Stunden aufgehängt).<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
<br />
=== Dateigrösse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Grösse tätig zu werden. Dazu muss diese Grösse allerdings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:reduceLogState.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Grösse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
Die oben beschriebene Möglichkeit ist für SQLite verwendbar. Zur Ermittlung der DB-Größe andere DB-Typen (aber auch für SQLite nutzbar) kann wie [[DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten#Gr.C3.B6.C3.9Fe_der_FHEM-Datenbank_ermitteln | hier]] beschrieben vorgegangen werden.<br />
<br />
<br />
== Performance-Optimierung ==<br />
Auch eine Datenbank kann mit der Zeit langsamer werden. Dies hängt von mehreren Faktoren ab:<br />
* Menge der gelogten Daten (zB. > 4-5 GB)<br />
* Eingesetzte Hardware (zB. langsame SD-Karte vs. schnelle SSD)<br />
* Eingesetztes Datenbanksystem (zB. SQLite, MySQL)<br />
* Komplexität der Abfragen (zB. für aufwändige Graphen oder Berechnungen)<br />
<br />
Diese Punkte sollen im folgenden diskutiert werden:<br />
<br />
<br />
=== Komplexität der Abfragen ===<br />
Dies ist kein Problem der Datenbank, sondern rein der Abfrage. Dem entsprechend muss die Optimierung auch in der Abfrage oder im Skript gesucht werden. Dies ist nicht Ziel dieses Abschnittes und wird hier nicht weiter behandelt.<br />
<br />
<br />
=== Eingesetztes Datenbanksystem ===<br />
Welches Datenbanksystem eingesetzt wird (zB. SQLite oder MySQL) hat auf die Performance der Datenbank gar keinen so großen Einfluss, wie vielleicht zuerst gedacht. Selbst SQLite kann problemlos Datenbanken mit etlichen GB Größe performant verarbeiten. Der Flaschenhals ist hier viel mehr die darunter liegende Hardware (s.u.).<br />
<br />
Die Performance der Datenbank an sich, kann aber durch verschiedene Maßnahmen verbessert werden:<br />
* Pflegemaßnahmen bzgl. der Daten<br />
* '''Erstellung von Indizes'''<br />
<br />
<br />
==== Menge der Daten und Pflegemaßnahmen bzgl. der Daten ====<br />
Die Menge der geloggten Daten hat natürlich Einfluss auf die Geschwindigkeit von Abfragen - je mehr Daten vorhanden sind, desto mehr Daten müssen auch durchforstet werden um eine Abfrage zu bedienen. Die Reduzierung der geloggten Datenmenge hat also direkten Einfluss auf die Größe und damit auch die Geschwindigkeit der Datenbank. Die Menge der zu loggenden Daten lässt sich an zwei Stellen einschränken:<br />
* bei der Definition jedes Devices (s. Kapitel oben)<br />
* bei der Festlegung des fhem-weiten Log-Levels (s. [[Loglevel]])<br />
<br />
Die Menge der bereits geloggten Daten kann zB. mit Hilfe von [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] verringert und optimiert werden, bspw.<br />
* löschen unnötiger Daten<br />
* vacuum der Datenbank<br />
<br />
Insgesamt haben diese Maßnahmen aber nur einen eingeschränkten Effekt auf die Performance der DB. Deutlich effektiver ist die Erstellung eines Index (s.u.).<br />
<br />
<br />
==== Erstellung von Indizes ====<br />
Die Erstellung von Indizes hat mit Abstand den größten Einfluss auf die Performance einer Datenbank (auf unveränderter Hardware). Extrem zusammengefasst ist ein Index eine extrem optimiertes Nachschlageverzeichnis für einen bestimmten Typ Daten (ein Index wie im Buch halt). Eine wunderbare Einführung in Indizes bietet [[https://use-the-index-luke.com/de|https://use-the-index-luke.com]].<br />
<br />
In fhem sind Indizes sogar sehr einfach einzurichten da die Datenbank-Nutzung sehr stark vorgegeben ist. Nahezu jede Abfrage folgt dem Schema ''Device -> Reading -> Datum -> Wert''. Ein Index kann genau diese Abfrage bedienen und beschleunigen. Ein Index nur über die Devices wäre ein erster Schritt, brächte aber noch keinen großen Gewinn (wie um Link oben gut beschrieben). Über die gesamten ersten drei Schritte erstellt (Device -> Reading -> Datum) bringt der Index aber sofort eine deutliche Geschwindigkeitssteigerung.<br />
<br />
Die Erstellung eines Index erfolgt direkt in der Datenbank (und nicht aus fhem heraus), hier am Beispiel einer SQLite-DB:<br />
<br />
Öffnen der DB:<br />
<pre> sudo sqlite3 fhem.db </pre><br />
<br />
Erzeugen des Index auf der DB-Konsole (das Semikolon am Ende ist wichtig):<br />
<pre> create index idx_device_reading_timestamp on history (device, reading, timestamp); </pre><br />
<br />
Verlassen der DB:<br />
<pre> .exit </pre><br />
<br />
Einzig zu berücksichtigen ist, dass dieser Index die Datenbank um bis zu 1/3 vergrößert. Er kann aber bei Bedarf auch wieder entfernt werden. Bei meiner 15 GB SQLite-Datei (auf einem Mac Mini mit SSD) hat dies ca. 15 min gedauert (den fhem hatte ich vorsichtshalber währenddessen deaktiviert).<br />
<br />
Sollte jemand spezielle Berechnungen oder Skripte ausführen, die nach einem anderen Abfrage-Schema arbeiten, könnte man dafür spezialisierte zusätzliche Indizes erstellen. Das sollte aber dann mit dem Wissen des obigen Links erarbeitet werden, da dann etwas mehr Hintergrundwissen sehr hilfreich ist.<br />
<br />
<br />
==== DB-Backup ====<br />
Ein anderer Aspekt, der eigentlich nichts mit der Performance der DB zu tun hat, ist der Einfluss aufs Backup. Wird bspw. ein Systembackup per RSYNC gemacht, muss bei SQLite immer die komplette ggf. riesige Datei gesynct werden - bei MySQL würden nur die veränderten DB-Elemente gesynct. Dies soll hier nicht weiter vertieft werden, sollte aber bei einer Gesamtstrategie bedacht werden.<br />
<br />
<br />
=== Eingesetzte Hardware ===<br />
fhem hat grundsätzlich sehr viele kleine Datenzugriffe, unabhängig davon ob FileLog oder DbLog eingesetzt wird. Deshalb ist der absolut größte Performance-Gewinn durch den Einsatz schneller Festplatten zu erreichen - ganz einfache Aussage: ''je schneller desto besser ;-)''. Konkret bietet eine SSD mit mind. 250MB/s Datenzugriff eine ordentliche Basis für jedes datengestützte System, wie den fhem.<br />
<br />
Wenn die Datenmenge größer und die Abfragen komplexer werden, müssen natürlich irgendwann auch die Prozessorleistung und der Arbeitsspeicher mit wachsen. Aber auch an einem Raspi wird eine SSD deutlich performanter sein, als eine einfache SD-Karte oder eine klassische rotierende Festplatte.<br />
<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=27619DbLog2018-08-07T12:23:44Z<p>Fabian: /* Datenbank migrieren */ Hinweis zu Größenproblemen eingefügt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])<br />
}}<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen in FHEM recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als {{Link2CmdRef|Lang=de|Anker=FileLog|Label=FileLog}} gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann FHEM die Log-Daten mittels {{Link2CmdRef|Lang=de|Anker=DbLog|Label=DbLog}} in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
;Hinweis:<br />
Reporting und Management von DbLog-Datenbankinhalten kann mit dem Modul [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] stattfinden.<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
Es wird empfohlen diese Datei zu kopieren und erst dann entsprechend zu bearbeiten. Am Besten kopiert man diese Datei in das FHEM Home Directory /opt/fhem/ und achtet auf die entsprechenden Rechte!<br />
chown fhem:dialout /opt/fhem/db.conf<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
Unbedingt beachten: bei Verwendung des Moduls configdb wird die Konfigurationsdatei aus der '''''Datenbank''''' gelesen. Deshalb ist es erforderlich, das File mittels <code>configdb fileimport db.conf </code> vorher zu importieren !<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es mehrere Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
* Ausschluß von Device/Reading-Kombinationen über das Attribut "excludeDevs". Es können [https://fhem.de/commandref_DE.html#devspec devspec] verwendet werden. <br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. {{Link2CmdRef|Lang=de|Anker=event-on-update-reading}})<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe {{Link2CmdRef}}.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
Die Datenbank ist relativ simpel gestaltet und besteht lediglich aus den folgenden beiden Tabellen:<br />
* current<br />
* history<br />
<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
==== current ====<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Um doppelte Einträge in der Tabelle zu vermeiden, wurden die Möglichkeit geschaffen Primary Keys zu definieren. Da in der Spalte <code>READING</code> u.U. bei verschiedenen Geräten gleiche Namen vorkommen können, sollte der Primary Key um den Gerätenamen erweitert werden. Der Primary Key sollte also aus <code>DEVICE</code> und <code>READING</code> bestehen. Um in der Datenbank ''fhem'' diesen PK zu setzen, kann folgender SQL Code verwendet werden:<br />
<br />
<syntaxhighlight lang="sql"><br />
ALTER TABLE `fhem`.`current` <br />
CHANGE COLUMN `DEVICE` `DEVICE` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
CHANGE COLUMN `READING` `READING` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
ADD PRIMARY KEY (`DEVICE`, `READING`);<br />
</syntaxhighlight><br />
<br />
==== history ====<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen oder Auswertungen mit [https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten DbRep] anzufertigen<br />
<br />
{{Todo|Ausbauen}}<br />
<br />
Um Problem beim Import von cacheFiles zu vermeiden, kann in der Datenbank ein PK angelegt werden, welcher Timestamp, Device und Reading umfasst. Dadurch werden doppelte Einträge wirksam verhindert.<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
Des Weiteren ist zu beachten: <br />
<br />
On-Off-Plots<br />
<br />
EG_Bad:window:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:0/eg<br />
<br />
unter Berücksichtigung von dim-Werten:<br />
<br />
EG_WoZi_Licht:value:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:($1eq"dim"?$2*0.01:0)/eg<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE INDEX Search_Idx ON `history` (DEVICE, READING, TIMESTAMP);<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Anstatt nano kann jeder andere kompatible Editor verwendet werden. Weiterhin bitte beachten, dass die hier genannten Befehle teilweise root-Rechte voraussetzen. Entweder komplett als root arbeiten, oder mittels sudo.<br />
<br />
Unter Ubuntu/debian: <br />
apt-get update && apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
Hinweis: im Folgenden ist "#" der normale Prompt und "mysql>" der prompt innerhalb mysql, dieser kann mit exit verlassen werden. <br />
<br />
Zum Test mal mit mysql verbinden:<br />
# mysql -p -u root<br />
Enter password:<br />
mysql> exit<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann die Datei /opt/fhem/contrib/dblog/db_create_mysql.sql als Vorlage verwendet und das Passwort und der Benutzername geändert werden. <br />
cd /opt/fhem/contrib/dblog/<br />
nano db_create_mysql.sql<br />
Dann wird die Datei eingelesen (root Passwort wird abgefragt): <br />
<br />
# mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
# mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
nano /opt/fhem/db.conf<br />
<br />
Jetzt kann unter FHEM ein DbLog-Device angelegt werden (mit dem beispiel wird alles geloggt: <br />
define logdb DbLog ./db.conf .*:.*<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in FHEM stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich.<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<syntaxhighlight lang="sql"><br />
# mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from history; # Achtung, kann sehr groß werden .... #<br />
</syntaxhighlight><br />
<br />
== Beispiel: Abfragescript PHP/MySQL ==<br />
Um eine schnelle Übersicht zu bekommen habe ich mir dieses Script geschrieben:<br />
<syntaxhighlight lang="php"><?php $pdo = new PDO('mysql:host=localhost;dbname=fhem', 'fhemuser', 'fhempasswort');<br />
echo '<h2>Tabelle Current</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th><th>Readings</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE, GROUP_CONCAT(DISTINCT READING ORDER BY READING DESC SEPARATOR '</li><li>') FROM current GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td><td><ol><li>" . $row[2] . "</li></ol></td></tr>";<br />
}<br />
echo "</table>";<br />
<br />
<br />
echo '<h2>Tabelle History</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE FROM history GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td></tr>";<br />
}<br />
echo "</table>";<br />
?><br />
</syntaxhighlight><br />
<br />
Bitte passt fhemuser und fhempasswort an. Das Ganze kommt dann nach ''/var/www/html/fhemdb.php'' und ist mit ''<IP>/fhemdb.php'' aufrufbar. Wenn ihr den 2. Block für die history Tabelle ausklammert oder entfernt läuft das Script viel schneller ab - klar die history Tabelle ist meist randvoll.<br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_splitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
<br />
Dazu muss der Modulautor in der [[DevelopmentModuleIntro#X_Initialize|Initialize-Funktion]] eine <code>DbLog_splitFn</code> bereitstellen:<br />
<br />
<syntaxhighlight lang="perl"><br />
sub X_Initialize($)<br />
{<br />
my ($hash) = @_;<br />
...<br />
$hash->{DbLog_splitFn} = "X_DbLog_splitFn";<br />
}<br />
</syntaxhighlight><br />
<br />
Die genaue Aufrufsyntax und Funktionweise einer DbLog_split-Funktion findet man [[DevelopmentModuleIntro#X_DbLog_split|hier]].<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in der Datenbank herumzuwühlen (s.u.). Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der {{Link2CmdRef|Lang=de|Anker=DbLog}} und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor FHEM stoppt, um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden, ohne FHEM stoppen zu müssen. <br />
<br />
Datenbanken kann man ohne weitere Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt FHEM stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
FHEM wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
== Datenbank migrieren ==<br />
Eine schöne Anleitung zur Migration von SQLite zu MySQL/MariaDB mit Hilfe von [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] findet sich hier: [https://demaya.de/fhem-umzug-sqlite-mysql-mariadb/].<br />
<br />
Hinweis: Wenn die SQLite-DB sehr groß wird, kann es sein, dass der oben beschriebene Weg nicht funktioniert (konkret war dies bei meiner 15 GB großen DB nicht möglich, der Prozess hat sich immer nach mehreren Stunden aufgehängt).<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
=== Dateigrösse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Grösse tätig zu werden. Dazu muss diese Grösse allerdings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:reduceLogState.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Grösse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
Die oben beschriebene Möglichkeit ist für SQLite verwendbar. Zur Ermittlung der DB-Größe andere DB-Typen (aber auch für SQLite nutzbar) kann wie [[DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten#Gr.C3.B6.C3.9Fe_der_FHEM-Datenbank_ermitteln | hier]] beschrieben vorgegangen werden.<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=25474DbLog2018-02-24T12:54:52Z<p>Fabian: Kapitel "Datenbank migrieren" eingefügt (nur kurzer Verweis auf externe Anleitung)</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])<br />
}}<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen in FHEM recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als {{Link2CmdRef|Lang=de|Anker=FileLog|Label=FileLog}} gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann FHEM die Log-Daten mittels {{Link2CmdRef|Lang=de|Anker=DbLog|Label=DbLog}} in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
;Hinweis:<br />
Reporting und Management von DbLog-Datenbankinhalten kann mit dem Modul [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] stattfinden.<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
Es wird empfohlen diese Datei zu kopieren und erst dann entsprechend zu bearbeiten. Am Besten kopiert man diese Datei in das FHEM Home Directory /opt/fhem/ und achtet auf die entsprechenden Rechte!<br />
chown fhem:dialout /opt/fhem/db.conf<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
Unbedingt beachten: bei Verwendung des Moduls configdb wird die Konfigurationsdatei aus der '''''Datenbank''''' gelesen. Deshalb ist es erforderlich, das File mittels <code>configdb fileimport db.conf </code> vorher zu importieren !<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es 2 Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. {{Link2CmdRef|Lang=de|Anker=event-on-update-reading}})<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe {{Link2CmdRef}}.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
Die Datenbank ist relativ simpel gestaltet und besteht lediglich aus den folgenden beiden Tabellen:<br />
* current<br />
* history<br />
<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
==== current ====<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Um doppelte Einträge in der Tabelle zu vermeiden, wurden die Möglichkeit geschaffen Primary Keys zu definieren. Da in der Spalte <code>READING</code> u.U. bei verschiedenen Geräten gleiche Namen vorkommen können, sollte der Primary Key um den Gerätenamen erweitert werden. Der Primary Key sollte also aus <code>DEVICE</code> und <code>READING</code> bestehen. Um in der Datenbank ''fhem'' diesen PK zu setzen, kann folgender SQL Code verwendet werden:<br />
<br />
<syntaxhighlight lang="sql"><br />
ALTER TABLE `fhem`.`current` <br />
CHANGE COLUMN `DEVICE` `DEVICE` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
CHANGE COLUMN `READING` `READING` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
ADD PRIMARY KEY (`DEVICE`, `READING`);<br />
</syntaxhighlight><br />
<br />
==== history ====<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen oder Auswertungen mit [https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten DbRep] anzufertigen<br />
<br />
{{Todo|Ausbauen}}<br />
<br />
Um Problem beim Import von cacheFiles zu vermeiden, kann in der Datenbank ein PK angelegt werden, welcher Timestamp, Device und Reading umfasst. Dadurch werden doppelte Einträge wirksam verhindert.<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
Des Weiteren ist zu beachten: <br />
<br />
On-Off-Plots<br />
<br />
EG_Bad:window:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:0/eg<br />
<br />
unter Berücksichtigung von dim-Werten:<br />
<br />
EG_WoZi_Licht:value:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:($1eq"dim"?$2*0.01:0)/eg<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE INDEX Search_Idx ON `history` (DEVICE, READING, TIMESTAMP);<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Anstatt nano kann jeder andere kompatible Editor verwendet werden. Weiterhin bitte beachten, dass die hier genannten Befehle teilweise root-Rechte voraussetzen. Entweder komplett als root arbeiten, oder mittels sudo.<br />
<br />
Unter Ubuntu/debian: <br />
apt-get update && apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
Hinweis: im Folgenden ist "#" der normale Prompt und "mysql>" der prompt innerhalb mysql, dieser kann mit exit verlassen werden. <br />
<br />
Zum Test mal mit mysql verbinden:<br />
# mysql -p -u root<br />
Enter password:<br />
mysql> exit<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann die Datei /opt/fhem/contrib/dblog/db_create_mysql.sql als Vorlage verwendet und das Passwort und der Benutzername geändert werden. <br />
cd /opt/fhem/contrib/dblog/<br />
nano db_create_mysql.sql<br />
Dann wird die Datei eingelesen (root Passwort wird abgefragt): <br />
<br />
# mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
# mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
nano /opt/fhem/db.conf<br />
<br />
Jetzt kann unter FHEM ein DbLog-Device angelegt werden (mit dem beispiel wird alles geloggt: <br />
define logdb DbLog ./db.conf .*:.*<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in FHEM stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich.<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<syntaxhighlight lang="sql"><br />
# mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from history; # Achtung, kann sehr groß werden .... #<br />
</syntaxhighlight><br />
<br />
== Beispiel: Abfragescript PHP/MySQL ==<br />
Um eine schnelle Übersicht zu bekommen habe ich mir dieses Script geschrieben:<br />
<syntaxhighlight lang="php"><?php $pdo = new PDO('mysql:host=localhost;dbname=fhem', 'fhemuser', 'fhempasswort');<br />
echo '<h2>Tabelle Current</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th><th>Readings</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE, GROUP_CONCAT(DISTINCT READING ORDER BY READING DESC SEPARATOR '</li><li>') FROM current GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td><td><ol><li>" . $row[2] . "</li></ol></td></tr>";<br />
}<br />
echo "</table>";<br />
<br />
<br />
echo '<h2>Tabelle History</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE FROM history GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td></tr>";<br />
}<br />
echo "</table>";<br />
?><br />
</syntaxhighlight><br />
<br />
Bitte passt fhemuser und fhempasswort an. Das Ganze kommt dann nach ''/var/www/html/fhemdb.php'' und ist mit ''<IP>/fhemdb.php'' aufrufbar. Wenn ihr den 2. Block für die history Tabelle ausklammert oder entfernt läuft das Script viel schneller ab - klar die history Tabelle ist meist randvoll.<br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_splitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
<br />
Dazu muss der Modulautor in der [[DevelopmentModuleIntro#X_Initialize|Initialize-Funktion]] eine <code>DbLog_splitFn</code> bereitstellen:<br />
<br />
<syntaxhighlight lang="perl"><br />
sub X_Initialize($)<br />
{<br />
my ($hash) = @_;<br />
...<br />
$hash->{DbLog_splitFn} = "X_DbLog_splitFn";<br />
}<br />
</syntaxhighlight><br />
<br />
Die genaue Aufrufsyntax und Funktionweise einer DbLog_split-Funktion findet man [[DevelopmentModuleIntro#X_DbLog_split|hier]].<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in der Datenbank herumzuwühlen (s.u.). Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der {{Link2CmdRef|Lang=de|Anker=DbLog}} und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor FHEM stoppt, um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden, ohne FHEM stoppen zu müssen. <br />
<br />
Datenbanken kann man ohne weitere Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt FHEM stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
FHEM wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
== Datenbank migrieren ==<br />
Eine schöne Anleitung zur Migration von SQLite zu MySQL/MariaDB findet sich hier: [https://demaya.de/fhem-umzug-sqlite-mysql-mariadb/].<br />
<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
=== Dateigrösse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Grösse tätig zu werden. Dazu muss diese Grösse allerdings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:reduceLogState.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Grösse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19424ReadingsGroup2017-02-04T17:15:29Z<p>Fabian: /* Inhalte berechnen */</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== mapping ===<br />
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um<br />
* den Zeilentitel gegen den Raumnamen auszutauschen (zB. [[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]])<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]])<br />
* größere Berechnungen in [[99_myUtils_anlegen|99_myUtils.pm]] aufzurufen (zB. [[ReadingsGroup#Enigma Receiver|Enigma Receiver]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueIcon ===<br />
valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (zB. [[ReadingsGroup#Auswahl über Reading-Namen, Status als Symbol dargestellt|einfach]], [[ReadingsGroup#Heizungswerte, Status und Regelmöglichkeit|etwas mehr]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueStyle ===<br />
valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)|einfach]], [[ReadingsGroup#Internal Values ausgeben|erweitert]], [[ReadingsGroup#Wertabhängige Farbgebung|komplex]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Inhalte berechnen ===<br />
Will man nur kleine Berechnungen machen und möchte diese aus irgendeinem Grund nicht in die [[99_myUtils_anlegen|99_myUtils.pm]] auslagern (zB. 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.]]).<br />
<br />
Im konkreten Beispiel ist via caldav ein Abfallkalender eingebunden, der die folgenden Einträge erzeugt:<br />
<br />
<source><br />
t_001_bdate 06.02.2017 2017-02-04 14:40:49<br />
t_001_btime 00:00:00 2017-02-04 14:40:49<br />
...<br />
t_001_summary Gelber Sack 2017-02-04 14:40:49<br />
</source><br />
<br />
Daraus lässt sich mit <code>readingsGroup</code> so direkt keine ordentliche Darstellung erzeugen. Gewünscht ist aber das folgende Format eines Zeilenentrags:<br />
<br />
<code>06.02.2017 Gelber Sack</code><br />
<br />
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:<br />
<br />
<source lang="perl"><br />
# die readingsGroup reagiert nur auf summary-Einträge ( .* steht für eine beliebige Anzahl beliebiger Zeichen)<br />
<br />
define Abfallkalender readingsGroup calvAbfallKalender:t_.*summary<br />
<br />
attr Abfallkalender valueFormat {<br />
use Time::Local;;<br />
# alle Einträge Bio... und 4-wöchige Rest... ignorieren<br />
if (not $VALUE =~ /Bio/ and <br />
not $VALUE =~ /Restmülltonne..4/) {<br />
# readingname für bdate zum summary erzeugen<br />
my $rBdate = $READING =~ s/summary/bdate/r;;<br />
# readingvalue für bdate auslesen<br />
my $vDate = ReadingsVal($DEVICE,$rBdate,"");;<br />
# wenn value 'tonne' enthält dieses entfernen<br />
if ($VALUE =~ /tonne/) {<br />
$vDate . " " . substr($VALUE,0,index($VALUE,'tonne'));;<br />
} else {<br />
"$vDate %VALUE";;<br />
}<br />
} else {<br />
undef;;<br />
}<br />
}<br />
</source><br />
Der Code in der cfg-Datei würde bei valueFormat zwischen den Hauptklammern immer ;;;; statt ;; und an jedem Zeilenende ein \ haben.<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19423ReadingsGroup2017-02-04T17:14:50Z<p>Fabian: /* Inhalte filtern */ Kap. "Inhalte berechnen" angelegt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== mapping ===<br />
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um<br />
* den Zeilentitel gegen den Raumnamen auszutauschen (zB. [[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]])<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]])<br />
* größere Berechnungen in [[99_myUtils_anlegen|99_myUtils.pm]] aufzurufen (zB. [[ReadingsGroup#Enigma Receiver|Enigma Receiver]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueIcon ===<br />
valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (zB. [[ReadingsGroup#Auswahl über Reading-Namen, Status als Symbol dargestellt|einfach]], [[ReadingsGroup#Heizungswerte, Status und Regelmöglichkeit|etwas mehr]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueStyle ===<br />
valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)|einfach]], [[ReadingsGroup#Internal Values ausgeben|erweitert]], [[ReadingsGroup#Wertabhängige Farbgebung|komplex]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Inhalte berechnen ===<br />
Will man nur kleine Berechnungen machen und möchte diese aus irgendeinem Grund nicht in die [[99_myUtils_anlegen|99_myUtils.pm]] auslagern (zB. 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.]]).<br />
<br />
Im konkreten Beispiel ist via caldav ein Abfallkalender eingebunden, der die folgenden Einträge erzeugt:<br />
<br />
<source><br />
t_001_bdate 06.02.2017 2017-02-04 14:40:49<br />
t_001_btime 00:00:00 2017-02-04 14:40:49<br />
...<br />
t_001_summary Gelber Sack 2017-02-04 14:40:49<br />
</source><br />
<br />
Daraus lässt sich mit <code>readingsGroup</code> so direkt keine ordentliche Darstellung erzeugen. Gewünscht ist aber das folgende Format eines Zeilenentrags:<br />
<br />
<code>06.02.2017 Gelber Sack</code><br />
<br />
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:<br />
<br />
<source lang="perl"><br />
# die readingsGroup reagiert nur auf summary-Einträge ( .* steht für eine beliebige Anzahl beliebiger Zeichen)<br />
<br />
define Abfallkalender readingsGroup calvAbfallKalender:t_.*summary<br />
<br />
attr Abfallkalender valueFormat {<br />
use Time::Local;;<br />
# alle Einträge Bio... und 4-wöchige Rest... ignorieren<br />
if (not $VALUE =~ /Bio/ and <br />
not $VALUE =~ /Restmülltonne..4/) {<br />
# readingname für bdate zum summary erzeugen<br />
my $rBdate = $READING =~ s/summary/bdate/r;;<br />
# readingvalue für bdate auslesen<br />
my $vDate = ReadingsVal($DEVICE,$rBdate,"");;<br />
# wenn value 'tonne' enthält dieses entfernen<br />
if ($VALUE =~ /tonne/) {<br />
$vDate . " " . substr($VALUE,0,index($VALUE,'tonne'));;<br />
} else {<br />
"$vDate %VALUE";;<br />
}<br />
} else {<br />
undef;;<br />
}<br />
}<br />
</source><br />
In der Code in der cfg-Datei würde bei valueFormat zwischen den Hauptklammern immer ;;;; statt ;; und an jedem Zeilenende ein \ haben.<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19420ReadingsGroup2017-02-04T16:32:51Z<p>Fabian: /* Attribute */</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== mapping ===<br />
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um<br />
* den Zeilentitel gegen den Raumnamen auszutauschen (zB. [[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]])<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]])<br />
* größere Berechnungen in [[99_myUtils_anlegen|99_myUtils.pm]] aufzurufen (zB. [[ReadingsGroup#Enigma Receiver|Enigma Receiver]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueIcon ===<br />
valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (zB. [[ReadingsGroup#Auswahl über Reading-Namen, Status als Symbol dargestellt|einfach]], [[ReadingsGroup#Heizungswerte, Status und Regelmöglichkeit|etwas mehr]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueStyle ===<br />
valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)|einfach]], [[ReadingsGroup#Internal Values ausgeben|erweitert]], [[ReadingsGroup#Wertabhängige Farbgebung|komplex]]).<br />
<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19419ReadingsGroup2017-02-04T16:32:01Z<p>Fabian: /* Attribute */ valueIcon und valueStyle grundlegend erklärt und Bsp. verlinkt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== mapping ===<br />
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um<br />
* den Zeilentitel gegen den Raumnamen auszutauschen (zB. [[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]])<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]])<br />
* größere Berechnungen in [[99_myUtils_anlegen|99_myUtils.pm]] aufzurufen (zB. [[ReadingsGroup#Enigma Receiver|Enigma Receiver]]).<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueIcon ===<br />
valueIcon wird verwendet um einer Zeile zusätzlich ein Symbol hinzuzufügen (zB. [[ReadingsGroup#Auswahl über Reading-Namen, Status als Symbol dargestellt|einfach]], [[ReadingsGroup#Heizungswerte, Status und Regelmöglichkeit|etwas mehr]]).<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueStyle ===<br />
valueStyle wird verwendet um die dargestellten Werte optisch anzupassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)|einfach]], [[ReadingsGroup#Internal Values ausgeben|erweitert]], [[ReadingsGroup#Wertabhängige Farbgebung|komplex]]).<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19418ReadingsGroup2017-02-04T16:20:53Z<p>Fabian: /* Attribute */ mapping grundlegend erklärt und Bsp. verlinkt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== mapping ===<br />
mapping wird verwendet um Elemente einer Zeile auszutauschen, bspw. um<br />
* den Zeilentitel gegen den Raumnamen auszutauschen (zB. [[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]])<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]]).<br />
Weitere Anwendungsbeispiele finden sich in den div. Beispielen unten und in der commandref.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=19417ReadingsGroup2017-02-04T16:07:36Z<p>Fabian: /* Attribute */ valueFormat grundlegend erklärt und Bsp. verlinkt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das FHEM-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
=== valueFormat ===<br />
valueFormat wird klassischerweise dazu genutzt um die dargestellten Werte zu formatieren - bspw. um einem Wert ein Einheitensymbol zu verpassen (zB. [[ReadingsGroup#Ausgabestil (hier rechtsbündig)]]). Man kann valueFormat aber auch für dynamische Darstellungen oder gar kleine Programmierungen "missbrauchen", bspw. um<br />
* einen Wert dynamisch durch ein Symbol zu ersetzen ohne exzessiv [[ReadingsGroup#mapping|mappen]] (s.o.) zu müssen (zB. [[ReadingsGroup#Reading-Werte zuordnen (Icon / Text)|Reading-Werte zuordnen]])<br />
* unerwünschte Werte auszufiltern (zB. [[ReadingsGroup#Inhalte filtern|Inhalte filtern]])<br />
* kleine Berechnungen durchzuführen, ohne diese in [[99_myUtils_anlegen|99_myUtils.pm]] zu erstellen (zB. [[ReadingsGroup#Inhalte berechnen|Inhalte berechnen]]).<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre><br />
define d_label dummy<br />
setreading d_label Heizung Heizung <br />
setreading d_label Temperatur Temperatur <br />
setreading d_label Status Status <br />
setreading d_label Wochenplan Wochenplan <br />
setreading d_label Werktag Werktag <br />
setreading d_label Samstag Samstag <br />
setreading d_label Sonntag Sonntag <br />
setreading d_label Zeitraum1 Zeitraum 1 <br />
setreading d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]]. (Zeilenweise in die Befehlszeile eintragen.)<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat><br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das FHEM Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FHEMWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="'.<br />
'width: 200px; '.<br />
'text-align:center; '.<br />
'border: 1px solid #ccc ;'. <br />
'background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '.<br />
'background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); '. <br />
'background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=PROPLANTA&diff=16540PROPLANTA2016-10-06T10:35:53Z<p>Fabian: Beispiel eingefügt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Auslesen von Wetterdaten der Webseite proplanta.de<br />
|ModType=d<br />
|ModForumArea=Unterstützende Dienste/Wettermodule<br />
|ModTechName=59_PROPLANTA.pm<br />
|ModOwner=tupol ({{Link2FU|5432|Forum}}/[[Benutzer Diskussion:Topos|Wiki]]) <br />
}}<br />
<br />
Modul zum Auslesen der Wetterdaten von www.proplanta.de<br />
<br />
<br />
== Voraussetzungen ==<br />
<br />
<br />
== Anwendung ==<br />
<br />
<br />
== Bekannte Probleme ==<br />
Die korrekte Darstellung des <code>weblink htmlCode</code> braucht evtl. etwas Zeit (lange Abrufzyklen).<br />
<br />
<br />
== Anwendungsbeispiel(e) ==<br />
[[Datei:Screenshot_Proplanta.png|600px]]<br />
<br />
<pre><br />
# erzeugt den Proplanta-Datenabruf<br />
define WetterProplanta PROPLANTA Siegen de<br />
attr WetterProplanta DbLogExclude .*<br />
attr WetterProplanta group Wettervorhersage (Proplanta)<br />
attr WetterProplanta room Wetter-vorhersage<br />
<br />
# erzeugt die Anzeige zum Datenabruf<br />
define VorschauProplanta weblink htmlCode {PROPLANTA_Html("WetterProplanta")}<br />
attr VorschauProplanta DbLogExclude .*<br />
attr VorschauProplanta group Wettervorhersage (Proplanta)<br />
attr VorschauProplanta room Wetter-vorhersage<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>DbLogExclude .*</code> die Daten sollen nicht ins Log geschrieben werden (hier [[DbLog]]) und es nicht "zumüllen"<br />
<br />
[[Kategorie:Gerätemodul]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Datei:Screenshot_Proplanta.png&diff=16539Datei:Screenshot Proplanta.png2016-10-06T10:33:22Z<p>Fabian: </p>
<hr />
<div></div>Fabianhttp://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&diff=16538DevelopmentModuleIntro2016-10-06T10:02:08Z<p>Fabian: Introsatz verschoben</p>
<hr />
<div>{{Hinweis|Dieser Text ist in Arbeit und muss noch an einigen Stellen ergänzt werden. <br />
Insbesondere beschreibt der Text derzeit nur einstufige Module. Die Abgrenzung zu zweistufigen Modulen und deren Eigenschaften sollte noch ergänzt werden.}}<br />
<br />
<br />
== Einleitung ==<br />
Um neue Geräte in FHEM verfügbar zu machen, kann man ein eigenes Modul in Perl schreiben, das automatisch von FHEM geladen wird, wenn ein passendes Gerät in FHEM definiert wird. Das Modul definiert dann wie mit dem Gerät kommuniziert wird, stellt Werte ("Readings") innerhalb von FHEM zur Verfügung oder erlaubt es das Gerät mit "Set"-Befehlen zu beeinflussen. Dieser Text soll den Einstieg in die Entwicklung eigener Module erleichtern.<br />
<br />
Mit dem FHEM-Befehl "define", der typischerweise in die zentrale Konfigurationsdatei fhem.cfg eingetragen wird, werden Geräte in FHEM definiert. Der Befehl sorgt dafür dass ein neues Modul bei Bedarf geladen wird und die Initialisierungsfunktion des Moduls aufgerufen wird. <br />
<br />
Damit das funktioniert müssen der Name des Geräts, der Name des Moduls und der Name der Initialisierungsfunktion zueinander passen. Das folgende Beispiel soll dies verdeutlichen:<br />
<br />
Ein Jeelink USB-Stick in einer Fritz-Box könnte beispielsweise mit dem Befehl <code>define JeeLink1 JeeLink /dev/ttyUSB0@57600</code> definiert werden.<br />
<br />
In der fhem.pl wird der define-Befehl verarbeitet, geprüft, ob ein Modul mit Namen JeeLink schon geladen ist und falls nicht ein Modul mit Namen XY_JeeLink.pm im Modulverzeichnis (bei einer FritzBox z.B. /var/media/ftp/fhem/FHEM) gesucht und dann geladen. <br />
Danach wird die Funktion JeeLink_Initialize aufgerufen.<br />
Die Moduldatei muss also nach dem Namen des Geräts benannt werden und eine Funktion mit dem Namen des Geräts und einer _initialize Funktion enthalten.<br />
In der Initialisierungsfunktion des Moduls werden dann die Namen der aller weiteren Funktionen des Moduls, die von fhem.pl aus aufgerufen werden, bekannt gemacht. Dazu wird der Hash - das ist die zentrale Datenstruktur für jede Instanz eines Gerätes - mit entsprechenden Werten gefüllt.<br />
<br />
== Der Hash einer Geräteinstanz ==<br />
Eine Besonderheit in Perl sind [http://de.wikipedia.org/wiki/Assoziatives_Array#Perl assoziative Arrays], (nicht ganz richtig als "Hash" bezeichnet) in denen die Adressierung nicht über eine Zählvariable erfolgt, sondern über einen beliebigen String. Die internen Abläufe bei der Adressierung führen dazu, dass die Speicherung in und der Abruf aus Hashes relativ langsam ist.<br />
<br />
Der zentrale Speicherort für Informationen einer Geräteinstanz bei FHEM ist ein solcher Hash, der seinerseits in fhem.pl von einem globalen Hash referenziert wird. <br />
<br />
<code>$defs{''Devicename''}</code> in fhem.pl verweist auf den Hash der Geräteinstanz. Diesen Verweis (also nur die Adresse) bekommen die Funktionen eines Moduls übergeben, das direkt von fhem.pl aufgerufen wird. In dem Hash stehen beispielsweise die internen Werte des Geräts, die im GUI als "Internals" angezeigt werden oder die Readings des Geräts. Beispiele:<br />
*<code>$hash{NAME}</code> enthält den Namen der Geräteinstanz, <br />
*<code>$hash{TYPE}</code> enthält die Typbezeichnung des Geräts <br />
*<code>$hash->{INTERVAL}</code> enthält ein Abfrageintervall<br />
<br />
==Ausführung von Modulen==<br />
FHEM führt Module normalerweise nicht parallel aus. Daher wäre es ungünstig wenn Module Werte von einem Gerät abfragen und dann auf die Antwort des Geräts warten. In dieser Zeit wäre der Rest von FHEM blockiert. Die Ein- und Ausgabe sollte ohne Blockieren erfolgen und die Verarbeitung mehrerer Ein- und Ausgabekanäle quasi parallel ermöglichen. <br />
<br />
Dafür werden in FHEM zwei zentrale Listen gepflegt, in der die Filedeskriptoren der geöffneten Kommunikatonsverbindungen gespeichert sein können. Auf Linux- bzw. Unix-basierten Plattformen wird der select-Befehl des Betriebssystems verwendet und entsprechend gibt es in FHEM eine selectlist, in der die Filedeskriptoren der Geräedateien (z.B. /dev/ttyUSBx etc.) gespeichert sind. <br />
<br />
In der zentralen Schleife von fhem.pl wird mit select überwacht, ob über eine der geöffneten Schnittstellen Daten zum Lesen anstehen. Wenn dies der Fall ist, dann wird die Lesefunktion (X_Read) des zuständigen Moduls aufgerufen, damit es die Daten entgegennimmt und die Schleife wird weiter ausgeführt.<br />
<br />
Auf Windows-Systemen funktioniert dies anders. Hier können USB/Seriell-Geräte nicht per select überwacht werden. In FHEM unter Windows werden daher diese Schnittstellen kontinuierlich abgefragt ob Daten bereitstehen. Dafür müssen Module zusätzlich zur Lesefunktion eine Abfragefunktion (X_Ready) implementieren, die prüft ob Daten zum Lesen anstehen. Auch auf Linux/Unix-Plattformen hat diese Funktion eine Aufgabe. Falls nämlich eine Schnittstelle ausfällt beziehungsweise ein CUL oder USB-zu-Seriell Adapter ausgesteckt wird, dann wird über diese Funktion regelmäßig geprüft ob die Schnittstelle wieder verfügbar wird.<br />
<br />
Innerhalb der eigentlichen Lesefunktion (X_Read) werden dann die Daten vom zugehörigen Gerät gelesen, das nötige Protokoll implementiert und Werte in Readings geschrieben.<br />
<br />
Auch wenn von einem Anwender über ein <code>get</code> Daten aktiv von einem Gerät angefordert werden sollte nicht blockierend gewartet werden. Eine asynchrone Ausgabe ist über asyncOutput möglich. Siehe {{Link2Forum|Topic=43771|Message=357870|LinkText=Beschreibung}} und {{Link2Forum|Topic=43771|Message=360935|LinkText=Beispiel}}. Weitere Anwendungsbeispiele finden sich im {{Link2Forum|Topic=43052|Message=353477|LinkText=PLEX Modul}} und im überarbeiteten und nicht-blockierenden {{Link2Forum|Topic=42771|Message=348498|LinkText= SYSSTAT Modul}}.<br />
<br />
== Readings ==<br />
Werte, die von einem Gerät gelesen werden und in FHEM zur Verfügung stehen werden Readings genannt. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielsweise <br />
*<code>$hash{READINGS}{Temp}{VAL}</code> für die Temperatur eines Fühlers<br />
*<code>$hash{READINGS}{Temp}{TIME}</code> für den Zeitstempel der Messung<br />
<br />
Für den lesenden Zugriff auf Readings steht die Funktion ReadingsVal($$$) zur Verfügung.<br />
<br />
Readings werden im statefile von FHEM automatisch zwischengespeichert, damit sie nach einem Neustart sofort wieder zur Verfügung stehen, auch bevor sie vom Modul neu gesetzt oder aktualisiert werden.<br />
<br />
Readings, die mit einem Punkt im Namen beginnen, haben eine funktionale Besonderheit. Sie werden im FhemWeb nicht angezeigt und können somit als "Permanentspeicher" innerhalb des Moduls genutzt werden.<br />
<br />
Zum Setzen von Readings sollen <br />
*bei Gruppen von Readings der Funktionsblock <code>readingsBeginUpdate</code>, <code>readingsBulkUpdate</code> (mehrfach wiederholt), <code>readingsEndUpdate</code><br />
*bei einzelnen Updates die Funktion <code>readingsSingleUpdate</code> <br />
aufgerufen werden. Dabei kann man auch angeben, ob dabei ein Event ausgelöst werden soll oder nicht. Events erzeugen spürbare Last auf dem System (siehe NotifyFn), das Ändern von Readings ohne dass dabei Events erzeugt werden jedoch nicht.<br />
<br />
Eine Sequenz zum Setzen von Readings könnte folgendermaßen aussehen:<br />
<br />
<pre><br />
readingsBeginUpdate($hash);<br />
readingsBulkUpdate($hash, $readingName1, $wert1 );<br />
readingsBulkUpdate($hash, $readingName2, $wert2 );<br />
readingsEndUpdate($hash, 1);<br />
</pre><br />
<br />
== Internals ==<br />
Werte, die das Modul intern als Teil des Hashes speichert, die aber keine Readings sind, nennt man Internals. Sie werden ebenfalls als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielswiese <code>$hash->{INTERVAL}</code> für ein Abfrageintervall, das beim Define-Befehl übergeben wurde und als Internal gespeichert wird. Internals werden jedoch im Gegensatz zu Readings nicht im statefile zwischengespeichert. <br />
<br />
Falls Werte wie das gerade erwähnte Intervall nicht über den Define-Befehl gesetzt werden sollen und im Betrieb einfach änderbar sein sollen, ist eine alternative Möglichkeit die Speicherung in so genannten Attributen. Dann würde man den Define-Befehl so implementieren, dass er kein Intervall übergeben bekommt und statt dessen nach dem Define-Befehl zusätzlich den Befehl <code>attr</code> erwarten.<br />
<br />
== Attribute ==<br />
Parameter einer Geräteinstanz können mit dem Befehl <code>attr</code> als so genannte Attribute gesetzt und damit dem Modul zur Verfügung gestellt werden. Attribute werden zusammen mit der Definition der Geräte beim Speichern der aktuellen Konfiguration von FHEM in die Konfigurationsdatei geschrieben, die auch bei jedem Neustart von FHEM wieder gelesen wird. Zur Laufzeit werden Attribute in der globalen Datenstruktur <code>$attr{$name}</code> gespeichert. Ein Attribut mit dem Namen <code>header</code> würde beispielsweise mit <code>$attr{$name}{header}</code> adressiert (<code>$attr{$name}->{'header'}</code> wäre eine alternative aber unübliche Schreibweise für die selbe Variable). <br />
<br />
Zum Auslesen solcher Attribute sollte die Funktion <code>AttrVal($$$)</code> verwendet werden.<br />
<br />
Welche Attribute ein Modul unterstützt sollte in der Funktion <code>[[#X_Initialize|X_Initialize]]</code> durch Setzen der Variable <code>$hash->{AttrList}</code> bekannt gemacht werden (siehe unten). Wenn beim Setzen von Attributen die Werte geprüft werden sollen oder zusätzliche Funktionalität implementiert werden muss, dann kann dies in der Funktion <code>[[#X_Attr|X_Attr]]</code> ([[#X_Attr|siehe unten]]) implementiert werden.<br />
<br />
== Die wichtigsten Funktionen in einem Modul ==<br />
Eine typische Grundfunktion eines einfachen Moduls ist das Auslesen von Werten von einem physischen Gerät und Bereitstellen dieser Werte innerhalb von FHEM als Readings. Das Geräte könnte beispielsweise an einem USB-Port angeschlossen sein. Folgende Funktionen könnte man beispielsweise in einem Modul mit Namen X implementieren:<br />
* [[#X_Initialize|X_Initialize]] (initialisiert das Modul und gibt de Namen der zusätzlichen Funktionen bekannt)<br />
* [[#X_Define|X_Define]] (wird beim <code>define</code> aufgerufen)<br />
* [[#X_Undef|X_Undef]] (wird beim <code>delete</code>, sowie <code>rereadcfg</code> aufgerufen. Dient zum Abbau von offenen Verbindungen, Timern, etc.)<br />
* [[#X_Delete|X_Delete]] (wird beim <code>delete</code> aufgerufen um das Gerät endgültig zu löschen)<br />
* [[#X_Set|X_Set]] (wird beim Befehl <code>set</code> aufgerufen um Daten an das Gerät zu senden)<br />
* [[#X_Get|X_Get]] (wird beim Befehl <code>get</code> aufgerufen um Daten vom Gerät abzufragen)<br />
* [[#X_Attr|X_Attr]] (wird beim Befehl <code>attr</code> aufgerufen um beispielsweise Werte zu prüfen)<br />
* [[#X_Read|X_Read]] (wird vom globalen select aufgerufen, falls Daten zur Verfuegung stehen)<br />
* [[#X_Parse|X_Parse]] (wird bei zweistufigen Modulen vom Dispatch aufgerufen und muss hier noch beschrieben werden)<br />
* [[#X_Ready|X_Ready]] (wird unter windows als ReadFn-Erstatz benoetigt bzw. um zu pruefen, ob ein Geraet wieder eingesteckt ist)<br />
* [[#X_Notify|X_Notify]] (falls man benachrichtigt werden will)<br />
* [[#X_Rename|X_Rename]] (falls ein Gerät umbenannt wird)<br />
* [[#X_Shutdown|X_Shutdown]] (wird beim Herunterfahren aufgeführt)<br />
<br />
Die Funktionen werden im folgenden beschrieben (soweit diese Seite inzwischen vollständig ist):<br />
<br />
=== X_Initialize ===<br />
<br />
<pre><br />
sub X_Initialize($)<br />
{<br />
my ($hash) = @_;<br />
...<br />
</pre><br />
<br />
Das <code>X</code> im Namen muss dabei auf den Namen des Moduls bzw. des definierten Gerätetyps geändert werden. Im Modul mit der Datei <code>36_JeeLink.pm</code> beispielsweise ist der Name der Funktion <code>JeeLink_Initialize</code>. Die Funktion wird von Fhem.pl nach dem Laden des Moduls aufgerufen und bekommt einen Hash für das Modul als zentrale Datenstruktur übergeben. <br />
<br />
Dieser Hash wird im globalen Hash %modules gespeichert. <code>$modules{$ModulName}</code> wäre dabei der Hash für das Modul mit dem Namen <code>$ModulName</code>. Es handelt sich also nicht um den oben beschriebenen Hash der Geräteinstanzen sondern einen Hash, der je Modul Werte enthält, beispielsweise auch die Namen der Funktionen, die das Modul implementiert und die fhem.pl aufrufen soll. Die Initialize-Funktion setzt diese Funktionsnamen, in den Hash des Moduls:<br />
<br />
<pre><br />
$hash->{DefFn} = "X_Define";<br />
$hash->{UndefFn} = "X_Undef";<br />
$hash->{DeleteFn} = "X_Delete";<br />
$hash->{SetFn} = "X_Set";<br />
$hash->{GetFn} = "X_Get";<br />
$hash->{AttrFn} = "X_Attr";<br />
$hash->{NotifyFn} = "X_Notify";<br />
$hash->{ReadFn} = "X_Read";<br />
$hash->{ReadyFn} = "X_Ready";<br />
$hash->{ShutdownFn} = "X_Shutdown";<br />
</pre><br />
<br />
<code>X</code> ist wieder durch den Modulnamen ohne die vorangestellte Zahl zu ersetzen. <br />
Entsprechend können auch die Funktionen <code>X_Read</code>, <code>X_Parse</code> etc. durch Zuweisung an <code>$hash->{ReadFn}</code> etc. bekannt gemacht werden.<br />
<br />
Darüber hinaus sollten die vom Modul unterstützten Attribute definiert werden:<br />
<br />
<pre><br />
$hash->{AttrList} =<br />
"do_not_notify:1,0 " . <br />
"header " .<br />
$readingFnAttributes; <br />
</pre><br />
<br />
In Fhem.pl werden dann die entsprechenden Werte beim Aufruf eines <code>attr</code>-Befehls in die globale Datenstruktur <code>$attr{$name}</code>, z.B. <code>$attr{$name}{header}</code> für das Attribut <code>header</code> gespeichert. Falls im Modul weitere Aktionen oder Prüfungen beim Setzen eines Attributs nötig sind, dann kann wie im Beispiel oben die Funktion <code>X_Attr</code> implementiert und in der Initialize-Funktion bekannt gemacht werden.<br />
<br />
Die Variable <code>$readingFnAttributes</code>, die im obigen Beispiel an die Liste der unterstützten Attribute angefügt wird, definiert Attributnamen, die dann verfügbar werden wenn das Modul zum Setzen von Readings die Funktionen readingsBeginUpdate, readingsBulkUpdate, readingsEndUpdate oder readingsSingleUpdate verwendet. In diesen Funktionen werden Attribute wie <code>event-min-interval</code> oder auch <code>event-on-change-reading</code> ausgewertet. Für Details hierzu siehe commandref.<br />
<br />
<br />
Des weiteren ist es möglich, das Verhalten von Autocreate zu beeinflussen.<br />
<code>x</code> ist durch den Namen der Geräte zu ersetzen. Legt ihr Geräte mit dem Namen LaCrosse an, dann sollte x durch LaCrosse ersetzt werden.<br />
<pre><br />
$hash->{AutoCreate} =<br />
{ "x.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", <br />
FILTER => "%NAME", <br />
GPLOT => "temp4hum4:Temp/Hum,"} };<br />
autocreateThreshold => "<count>:<timeout>" <br />
</pre><br />
Mit <code>ATTR =></code> können Vordefinierte Attribute beim Anlegen definiert werden.<br />
Der Wert von <code>FILTER</code> wird als Regex verwendet, wenn ein Filelog angelegt wird. Damit könnt ihr steuern, welche Events ins Filelog komme. Definiert ihr das Feld <code>FILTER</code> nicht, gebt jedoch andere Felder an, dann kann kein filelog mehr automatisch durch autocreate angelegt werden!<br />
Mit Hilfe von <code>GPLOT</code> kann ein Plot angelegt werden. Mit der Angabe definiert ihr, welcher GPLOT angelegt wird.<br />
Mittels <code>autocreateThreshold</code> wird beeinflusst, wie oft <code>count</code>(default 2) und in welchem Zeitabstand <code>timeout</code> (default 60 Sekunden) die gleiche Nachricht empfangen werden muss, damit ein Gerät per autocreate angelegt wird. <br />
Das Verhalten, kann vom Anwender mittels Attribut <code>autocreateThreshold</code> im device "autocreate" überschrieben werden.<br />
<br />
<br />
Das Parsen der Parameter der define, get und set Kommandos sowie deren Übergabe an die DefFn, GetFn und SetFn lässt sich mit<br />
<pre>$hash->{parseParams} = 1;</pre> beeinflussen. Sobald es gesetzt ist wird automatisch [[DevelopmentModuleAPI#parseParams|parseParams]] aufgerufen und die an X_Define, X_Get und X_Set übergebenen Parameter ändern sich wie weiter unten beschrieben.<br />
<br />
=== X_Define ===<br />
Die Define-Funktion eines Moduls wird von Fhem aufgerufen wenn der Define-Befehl für ein Geräte ausgeführt wird und das Modul bereits geladen und mit der Initialize-Funktion initialisiert ist. Sie ist typischerweise dazu da, die übergebenen Parameter zu prüfen und an geeigneter Stelle zu speichern sowie einen Kommunikationsweg zum Gerät zu öffnen (z.B. TCP-Verbindung, USB-Schnittstelle o.ä.)<br />
Sie beginnt typischerweise mit:<br />
<br />
<pre><br />
sub X_Define($$)<br />
{<br />
my ( $hash, $def ) = @_;<br />
my @a = split( "[ \t][ \t]*", $def );<br />
...<br />
</pre><br />
<br />
Als Übergabeparameter bekommt die Define-Funktion den Hash der Geräteinstanz sowie den Rest der Parameter, die im Befehl angegeben wurden. Welche und wie viele Parameter <br />
akzeptiert werden ist Sache dieser Funktion. Im obigen Beispiel wird alles nach dem übergebenen Hash in ein Array aufgeteilt und so können die vom Modul bzw. der Define-Funktion erwarteten Werte über das Array der Reihe nach verarbeitet werden:<br />
<br />
<pre><br />
my $name = $a[0];<br />
my $url = $a[2];<br />
my $inter = 300;<br />
if(int(@a) == 4) { <br />
$inter = $a[3]; <br />
if ($inter < 5) {<br />
return "interval too small, please use something > 5, default is 300";<br />
}<br />
}<br />
</pre><br />
<br />
<br />
Neu: Zum Aufteilen und Parsen von <code>$def</code> lässt sich [[DevelopmentModuleAPI#parseParams|parseParams]] verwenden. Wenn in X_Initialize <pre>$hash->{parseParams} = 1;</pre> gesetzt wurde dann wird parseParams automatisch aufgerufen und X_Define ändert sich wie folgt:<br />
<pre><br />
sub X_Define($$$)<br />
{<br />
my ( $hash, $a, $h ) = @_;<br />
...<br />
</pre><br />
<br />
<br />
Damit die übergebenen Werte auch anderen Funktionen zur Verfügung stehen und an die jeweilige Geräteinstanz gebunden sind, werden die Werte typischerweise als Internals im Hash der Geräteinstanz gespeichert:<br />
<br />
<pre><br />
$hash->{url} = $url;<br />
$hash->{Interval} = $inter;<br />
</pre><br />
<br />
Wenn eine physische Schnittstelle geöffnet werden soll und dann bei verfügbaren Eingabedaten eine Lese-Funktion von Fhem aufgerufen werden soll, dann kann man in der Define-Funktion die Funktion DevIo_OpenDev aufrufen, die sich um alles weitere kümmert. Sie öffnet die Schnittstelle und fügt den Filedeskriptor an die globale Liste offener Verbindungen (selectlist / readyfnlist) an. Damit kann Fhem in seiner Hauptschleife erkennen, von welchem Gerät Daten bereit stehen und die zuständigen Funktionen aufrufen:<br />
<br />
<pre><br />
my $ret = DevIo_OpenDev( $hash, 0, "X_DevInit" );<br />
</pre><br />
<br />
Die optionale Funktion <code>X_DevInit</code> wird zur weiteren Initialisierung der Verbindung von <code>DevIo_OpenDev</code> aufgerufen. Der zweite Übergabeparameter an <code>DevIo_OpenDev</code> (hier <code>0</code>) steht für reopen und wird benötigt, da die Funktion auch aufgerufen wird, wenn ein USB-Geräte beispielsweise im Betrieb aus- und wieder eingesteckt wird. In diesem Fall wird die Funktion mit <code>1</code> aufgerufen.<br />
<br />
=== X_Undef ===<br />
<br />
Die <code>Undef</code>-Funktion wird aufgerufen wenn ein Gerät mit <code>delete</code> gelöscht wird oder bei der Abarbeitung des Befehls rereadcfg, der ebenfalls alle Geräte löscht und danach das Konfigurationsfile neu abarbeitet. Entsprechend müssen in der Funktion typische Aufräumarbeiten durchgeführt werden wie das saubere Schließen von Verbindungen oder das Entfernen von internen Timern sofern diese im Modul zum Pollen verwendet wurden (siehe später). <br />
<br />
Zugewiesene Variablen im Hash der Geräteinstanz, Internals oder Readings müssen hier nicht gelöscht werden. In fhem.pl werden die entsprechenden Strukturen beim Löschen der Geräteinstanz ohnehin vollständig gelöscht.<br />
<br />
Beispiel:<br />
<pre><br />
sub X_Undef($$) <br />
{ <br />
my ( $hash, $name) = @_; <br />
DevIo_CloseDev($hash); <br />
RemoveInternalTimer($hash); <br />
return undef; <br />
}<br />
</pre><br />
<br />
=== X_Delete ===<br />
<br />
Die <code>Delete</code>-Funktion ist das Gegenstück zur <code>Define</code>-Funktion und wird aufgerufen wenn ein Gerät mit <code>delete</code> gelöscht wird. <br />
<br />
Wenn ein Gerät mittels <code>delete</code> gelöscht wird, wird zuerst die <code>[[#X_Undef|Undef]]</code>-Funktion aufgerufen um offene Verbindungen abzubauen, anschließend wird die <code>Delete</code>-Funktion aufgerufen. Diese dient eher zum aufräumen von Dateien, welche durch das Modul evtl. für dieses Gerät spezifisch erstellt worden sind. Es geht hier also eher darum, alle Spuren sowohl im laufenden FHEM-Prozess, als auch Dateien oder Verbindungen zu löschen die mit diesem Gerät zu tun haben.<br />
<br />
Dies kann z.B. folgendes sein:<br />
<br />
* Löschen von Dateien im Dateisystem die während der Nutzung dieses Geräts angelegt worden sind.<br />
* Lösen von evtl. Pairings mit dem physikalischen Gerät <br />
<br />
Beispiel:<br />
<pre><br />
sub X_Delete($$) <br />
{ <br />
my ( $hash, $name ) = @_; <br />
<br />
# Löschen von Geräte-assoziiertem Temp-File<br />
unlink($attr{global}{modpath}."/FHEM/FhemUtils/$name.tmp";)<br />
} <br />
</pre><br />
<br />
=== X_Get ===<br />
Die Get-Funktion wird aufgerufen wenn der Fhem-Befehl <code>get</code> mit einem Gerät dieses Moduls ausgeführt wird. Mit <code>get</code> werden typischerweise Werte von einem Gerät abgefragt. Einige Module verwenden für diese Funktion einen Hash im Modul, der die möglichen <code>get</code>-Optionen mit zusätzlichen Werten definiert:<br />
<br />
<pre><br />
my %X_gets = (<br />
"TempSoll" => "XY",<br />
"Steilheit" => "Z"<br />
);<br />
</pre><br />
In der Get-Funktion selbst werden dann die übergebenen Parameter gegen diesen Hash geprüft.<br />
<br />
Beispiel:<br />
<br />
<pre><br />
sub X_Get($@)<br />
{<br />
my ( $hash, @a ) = @_;<br />
return "\"get X\" needs at least one argument" if ( @a < 2 );<br />
my $name = shift @a;<br />
my $opt = shift @a;<br />
if(!$X_gets{$opt}) {<br />
my @cList = keys %X_gets;<br />
return "Unknown argument $opt, choose one of " . join(" ", @cList);<br />
}<br />
...<br />
</pre><br />
<br />
Die Ausgabe der Meldung mit <code>unknown ... choose one of ...</code> ist dabei wichtig, da sie im GUI-Modul verwendet wird um die möglichen <code>get</code>-Optionen zu ermitteln und als Auswahl anzubieten. Im weiteren Verlauf der Ger-Funktion könnte man dann mit dem physischen Gerät kommunizieren und den gefragten Wert abfragen und diesen als Return-Wert der Get-Funktion zurückgeben.<br />
<br />
<br />
Neu: Wenn in X_Initialize <pre>$hash->{parseParams} = 1;</pre> gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams]] automatisch aufgerufen und X_Get ändert sich wie folgt:<br />
<pre><br />
sub X_Get($$$)<br />
{<br />
my ( $hash, $a, $h ) = @_;<br />
...<br />
</pre><br />
<br />
=== X_Set ===<br />
Die Set-Funktion ist das Gegenteil zur Get-Funktion. Sie ist dafür gedacht, Werte zum physischen Gerät zu schicken. Falls nur interne Werte im Modul gesetzt werden sollen, so sollte statt Set die Attr-Funktion verwendet werden. Attribute werden bei Save-Config auch in der Fhem.cfg gesichert. Set-Befehle nicht.<br />
<br />
Eine Set-Funktion ist ähnlich aufgebaut wie die Get-Funktion, sie bekommt jedoch nach dem Namen der Option auch den zu setzenden Wert übergeben.<br />
<br />
Beispiel:<br />
<pre><br />
sub X_Set($@)<br />
{<br />
my ( $hash, @a ) = @_;<br />
return "\"set X\" needs at least an argument" if ( @a < 2 );<br />
my $name = shift @a;<br />
my $opt = shift @a;<br />
my $value = join("", @a);<br />
<br />
if(!defined($X_sets{$opt})) {<br />
my @cList = keys %X_sets;<br />
return "Unknown argument $opt, choose one of " . join(" ", @cList);<br />
}<br />
</pre><br />
<br />
<br />
Neu: Wenn in X_Initialize <pre>$hash->{parseParams} = 1;</pre> gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams]] automatisch aufgerufen und X_Set ändert sich wie folgt:<br />
<pre><br />
sub X_Set($$$)<br />
{<br />
my ( $hash, $a, $h ) = @_;<br />
...<br />
</pre><br />
<br />
<br />
Das GUI FHEM-Web kann für die einzelnen Set-Optionen, die das Modul versteht auch automatisch Eingabehilfen wie Drop-Down Boxen oder Slider erzeugen. In der Detailansicht des GUI kann der Anwender dann die jeweiligen Werte komfortabel auswählen. Dafür muss die Set-Funktion, wenn sie mit der Option <code>?</code> aufgerufen wird, nicht nur einen Text mit <code>"Unknwon ... choose one of ..."</code> zurückgeben sondern den einzelnen Set-Optionen in diesem Rückgabetext nach einem Doppelpunkt Zusatzinformationen anhängen.<br />
Meist prüft man in den Modulen gar nicht auf die Option <code>?</code> sondern gibt generell bei unbekannten Optionen diesen Text zurück.<br />
<br />
Beispiel:<br />
<pre><br />
if(!defined($X_sets{$opt})) {<br />
return "Unknown argument $opt, choose one of mode:verbose,ultra,relaxed turbo:NoArg";<br />
}<br />
</pre><br />
<br />
Mit Kommata getrennte Werte ergeben eine Drop-Down Liste, mit der der User die Werte auswählen kann<br />
<pre>timer:30,120,300<br />
mode:verbose,ultra,relaxed</pre><br />
<br />
Wird kein Doppelpunkt zum Kommando angegeben, so wird eine Eingabezeile angezeigt, die die freie Eingabe eines Wertes erlaubt.<br />
<br />
Man kann jedoch die Eingabe-/Auswahlmöglichkeiten durch Widgets vereinfachen. Dazu gibt man hinter dem Doppelpunkt einen Widgetnamen und widgetspezifische Parameter an. Es existieren mehrere solcher Widgets in FHEMWEB. Die gebräuchlichsten sind:<br />
<br />
{| class="wikitable"<br />
|-<br />
! Zusatz !! Beispiel !! Beschreibung<br />
|-<br />
| '''noArg''' || <code>reset:noArg</code>|| Es werden keine weiteren Argumente mehr benötigt. In so einem Fall wird bei der Auswahl keine Textbox oder ähnliches angezeigt, da keine weiteren Argumente für diesen Befehl notwendig sind.<br />
|-<br />
| '''slider''':<min>,<step>,<max> || <code>dim:slider,0,1,100</code>|| Es wird ein Schieberegler angezeigt um den Parameter auszuwählen. Dabei werden als Zusatzparameter Minimum, Schrittweite und Maximum angegeben.<br />
|-<br />
| '''colorpicker''' || <code>rgb:colorpicker,RGB</code>|| es wird ein Colorpicker angezeigt, der dem Anwender die Auswahl einer Farbe ermöglicht. Bitte dazu auch den Wiki Artikel zum Colorpicker lesen: [[Color#Colorpicker]]<br />
|-<br />
| '''multiple''' || <code>group:multiple,Telefon,Multimedia,Licht,Heizung</code> || Es erscheint ein Auswahldialog, wo man verschiedene Werte durch klicken auswählen kann. Optional kann man in einem Freitext eigene Werte ergänzen. dieser Dialog wird bspw. bei der Raum-Auswahl (Attribut "room") oder der Gruppen-Auswahl (Attribut "group") in FHEMWEB genutzt. <br />
|-<br />
| '''sortable''' || <code>command:sortable,monday,tuesday,...</code> || Es erscheint ein Auswahldialog, wo man verschiedene Werte auswählen und sortieren kann. Man kann dabei Werte durch Klicken auswählen und durch Drag'n'Drop sortieren.<br />
|}<br />
<br />
Es gibt noch weitere solcher Widgets. Eine genaue Auflistung dazu findet sich in der [http://fhem.de/commandref.html#widgetOverride commandref] unter widgetOverride zu FHEMWEB.<br />
<br />
'''Hinweise'''<br />
<br />
- Damit in einer Eingabe bereits der aktuelle Wert vorbelegt bzw. in einer Auswahlliste der aktuelle Wert vorselektiert ist, muss es im Modul bzw. Gerät ein Reading mit dem gleichen Namen wie die Set-Option geben. Der Wert des gleichnamigen Readings wird dann als Vorbelegung / Vorselektion verwendet. <br />
<br />
- bei den üblichen Kommandos wie on off sollte man auf noArg verzichten, da diese durch FHEMWeb automatisch in der Raumübersicht angezeigt werden. Wenn man hier noArg spezifiziert, so werden diese nicht neben dem Modul in der Raumübersicht angezeigt und der User muss sich diese vie webCmd dann erst selbst definieren, was natürlich unschön ist<br />
<br />
- der User kann sich in der Raumübersicht nach wie vor via webCmd eine entsprechende Steuerung anlegen.<br />
<br />
=== X_Attr ===<br />
Die Attr-Funktion implementiert Prüfungen der bei einem <code>attr</code> übergebenen Werte und eventuell zusätzliche Aktionen wenn ein Attribut gesetzt wird. Die Liste der möglichen Attribute wird in der <code>[[#X_Initialize|X_Initialize]]-Funktion</code> definiert ([[#X_Initialize|siehe oben]]). Fhem ruft bei einem Attr-Befehl die zuständige <code>X-Attr-Funktion</code> auf und wenn diese keine Fehlermeldung sondern <code>undef</code> zurückgibt, dann schreibt fhem.pl die bei <code>attr</code> angegebenen Werte in die jeweilige Datenstruktur <code>$attr{$name}-> ...</code><br />
<br />
Beispiel:<br />
<br />
<pre><br />
X_Attr(@)<br />
{<br />
my ($cmd,$name,$aName,$aVal) = @_;<br />
# $cmd can be "del" or "set"<br />
# $name is device name<br />
# aName and aVal are Attribute name and value<br />
if ($cmd eq "set") {<br />
if ($aName eq "Regex") {<br />
eval { qr/$aVal/ };<br />
if ($@) {<br />
Log3 $name, 3, "X: Invalid regex in attr $name $aName $aVal: $@";<br />
return "Invalid Regex $aVal";<br />
}<br />
}<br />
}<br />
return undef;<br />
}<br />
</pre><br />
<br />
Zusätzlich ist es möglich auch übergebene Attributwerte zu normalisieren und korrigieren, indem man im Parameterhash den ursprünglichen Wert anpasst. Dies erfolgt im Beispiel über die Modifikation des Wertes mit Index 3 im Parameterarray, also <code>$_[3]</code>.<br />
<br />
Die Attr-Funktion bekommt nicht den Hash der Geräteinstanz übergeben, da sie ja auch keine Werte dort speichern muss, sondern den Befehl <code>set</code> oder <code>del</code> je nachdem ob ein Attribut gesetzt oder gelöscht wird, den Namen der Geräteinstanz sowie den Namen des Attributs und seinen Wert.<br />
Im obigen Beispiel wird für ein Attribut mit Namen Regex geprüft ob die Regex fehlerhaft ist. Falls sie ok ist, wird <code>undef</code> zurückgegeben und fhem.pl speichert den Wert des Attributs.<br />
<br />
Falls man Attribute mit Platzhaltern definiert (Wildcard-Attribute), z.B. mit<br />
<pre><br />
$hash->{AttrList} =<br />
"reading[0-9]*Name " .<br />
# usw.<br />
</pre><br />
dann können Anwender Attribute wie reading01Name, reading02Name etc. setzen. Leider funktioniert das bisher nicht durch Klicken, da Fhemweb nicht alle denkbaren Ausprägungen in einem Dropdown anbieten kann. Der Benutzer muß solche Attribute über den <code>attr</code> Befehl eintippen.<br />
<br />
Man kann jedoch in der Attr-Funktion neu gesetzte Ausprägungen von Wildcard-Attributen an die gerätespezifische userattr-Variable anfügen. Dann können bereits gesetzte Attribute in Fhemweb durch Klicken ausgewählt und geändert werden.<br />
Dazu reicht ein Aufruf von <br />
<br />
<pre><br />
addToDevAttrList($name, $aName);<br />
</pre><br />
<br />
in der Attr-Funktion wenn ein Attribut gesetzt wird.<br />
<br />
=== X_Read ===<br />
<br />
Die X_Read-Funktion wird aus der Hauptschleife von FHEM aus aufgerufen wenn das Gerät, für das das Modul zuständig ist, Daten bereit gestellt hat, die gelesen werden können. Im folgenden Beispiel wird über eine serielle Schnittstelle (beziehungsweise über einen USB-To-Seriell-Konverter) von einem angeschlossenen Gerät gelesen. Dazu werden die bisher verfügbaren Daten mit der Funktion <code>DevIo_SimpleRead</code> gelesen. Da die Übertragung möglicherweise noch nicht vollständig ist, kann es sein, dass kurz darauf die X_Read-Funktion wieder aufgerufen wird und ein weiterer Teil oder der Rest der Daten gelesen werden kann.<br />
Die Funktion muss daher prüfen ob schon alle erwarteten Daten angekommen sind und gegebenenfalls die bisher gelesenen Daten zwischenspeichern. Es bietet sich an, dies im Hash der Geräteinstanz zu tun. Im Beispiel ist dies <code>$hash->{buffer}</code> an den die jeweils gelesenen Daten angehängt werden bis die folgende Prüfung ein für das jeweilige Protokoll passendes Frame identifiziert.<br />
<br />
<pre><br />
sub X_Read($)<br />
{<br />
my ($hash) = @_;<br />
my $name = $hash->{NAME};<br />
<br />
# read from serial device<br />
my $buf = DevIo_SimpleRead($hash); <br />
return "" if ( !defined($buf) );<br />
<br />
# convert to hex string to make parsing with regex easier<br />
$hash->{buffer} .= unpack ('H*', $buf); <br />
Log3 $name, 5, "Current buffer content: " . $hash->{buffer};<br />
<br />
# did we already get a full frame?<br />
if ($hash->{buffer} =~ "ff1002(.{4})(.*)1003(.{4})ff(.*)") <br />
...<br />
</pre><br />
<br />
Die zu lesenden Nutzdaten können dann je nach Protokoll des Geräts beispielsweise an einer festgelegten Stelle im Frame (dann in <code>$hash->{buffer}</code>) stehen oder aus dem Kontext mit einem Regex-Match extrahiert werden und in Readings gespeichert werden (siehe unten).<br />
<br />
=== X_Ready ===<br />
<br />
Wird im Main-Loop aufgerufen falls das Modul in <code>@readyfnlist</code> existiert. Prüft, ob das Gerät Daten zum empfangen hat. Beim Initialisieren des Moduls sollte es sich in die Liste eintragen.<br />
<br />
Weiterführende Informationen: [[#KommunikationvomGerätZuLogischenModulen]]<br />
<br />
Beispiel:<br />
<pre><br />
sub X_Ready($)<br />
{<br />
my ($hash) = @_;<br />
return DevIo_OpenDev($hash, 1, undef )<br />
if ( $hash->{STATE} eq "disconnected" );<br />
<br />
# This is relevant for windows/USB only<br />
my $po = $hash->{USBDev};<br />
my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po->status;<br />
return ( $InBytes > 0 );<br />
}<br />
</pre><br />
<br />
=== X_Notify ===<br />
<br />
Die X_Notify-Funktion wird aus der Funktion DoTrigger in fhem.pl heraus aufgerufen wenn ein Modul Events erzeugt hat. Damit kann ein Modul auf Events anderer Module reagieren. Typische Beispiele sind das Filelog-Modul oder das Average-Modul. Average reagiert auf Events anderer Module und erweitert diese mit der Berechnung von Tages- und Monats-Durchschnittswerten.<br />
<br />
Die Notify-Funktion bekommt dafür zwei Hash-Referenzen übergeben: den Hash des eigenen Geräts und den Hash des Geräts, das die Events erzeugt hat. <br />
Über den Hash des eigenen Geräts kann die Notify-Funktion beispielsweise auf die Internals oder Attribute des eigenen Geräts zugreifen.<br />
Über den Hash des Gerätes und die <code>deviceEvents</code> Funktion kann auf die aktuellen Events zugegriffen werden. Über den zweiten Parameter dieser Routine lässt sich bestimmen ob für ads Reading <code>state</code> ein 'normales' Event (d.h. in der form <code><reading>: <wert></code>) erzeugen soll (Wert: 1) oder ob z.b. aus Gründen der rückwärts Kompatibilität ein Event ohne <code><reading>: </code> erzeugt werden soll. Falls dem Anwender die Wahl des für state verwendeten Formats überlassen werden soll ist hierzu das <code>addStateEvent</code> Attribut vorzusehen.<br />
<br />
Der direkte Zugriff auf <code>$hash->{CHANGED}</code> ist nicht mehr zu empfehlen.<br />
<br />
Beispiel:<br />
<pre><br />
sub X_Notify($$)<br />
{<br />
my ($own_hash, $dev_hash) = @_;<br />
my $ownName = $own_hash->{NAME}; # own name / hash<br />
<br />
return "" if(IsDisabled($ownName)); # Return without any further action if the module is disabled<br />
<br />
my $devName = $dev_hash->{NAME}; # Device that created the events<br />
<br />
my $events = deviceEvents($dev,1);<br />
return if( !$events );<br />
<br />
foreach my $event (@{$events}) {<br />
$event = "" if(!defined($event));<br />
<br />
# Examples:<br />
# $event = "readingname: value" <br />
# or<br />
# $event = "INITIALIZED" (for device "global")<br />
#<br />
# processing $event with further code<br />
}<br />
}<br />
</pre><br />
<br />
Da die Notify-Funktion für jedes Gerät mit allen seinen Events aufgerufen wird, muss sie in einer Schleife alle Events prüfen und entscheiden, ob es mit dem jeweiligen Event etwas tun möchte. Ein Gerät, das die Notify-Funktion implementiert sieht dafür typischerweise einen regulären Ausdruck vor, der für die Filterung verwendet wird.<br />
<br />
Wenn man nur gezielt von bestimmten Definitionen Events erhalten will, kann man diese auch in Form einer kommaseparierten Liste von Definitions-Namen in <code>$hash->{NOTIFYDEV}</code> angeben. Bspw. kann man in der Define-Funktion dort diesen Wert setzen. Dadurch wird die Notify-Funktion nur aufgerufen wenn eines der dort gelisteten Definitionen ein Event erzeugt hat. Ein typischer Fall ist die Begrenzung von Events auf "global":<br />
<br />
<pre><br />
in der Define-Funktion:<br />
<br />
$hash->{NOTIFYDEV} = "global";<br />
$hash->{NOTIFYDEV} = "global,Definition_A,Definition_B";<br />
</pre><br />
<br />
Dies schont insbesondere bei grossen Installationen Ressourcen, da die Notify-Funktion nicht sämtliche Events, sondern nur noch Events der hier gelisteten Definitionen erhält. Dadurch erfolgen deutlich weniger Aufrufe der Notify-Funktion, was Systemressourcen schont.<br />
<br />
Als anschauliches Beispiel und für weitere Details eignet sich das Modul 98_Average.pm. Es ist aber (noch) nicht auf deviceEvents umgestellt da es durch das Erzeugen zusätzlicher Events im Quelldevice eine Sonderstellung hat.<br />
<br />
ToDo: NotifyOrderPrefix ?<br />
<br />
=== X_DbLog_splitFn ===<br />
Mit der DbLog_SplitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br><br />
Eingangsparameter: <br><br />
1. Das generierte Event<br><br />
2. das eventgenerierende Device<br><br />
Rückgabewerte: Array: Reading/Value/Unit<br />
<br />
Beispiel:<br />
<pre><br />
sub X_DbLog_splitFn($$)<br />
{<br />
my ($event, $device) = @_;<br />
my ($reading, $value, $unit);<br />
my $hash = $defs{$device}<br />
<br />
if($event =~ m/temperature/) {<br />
$reading = 'temperature';<br />
$value = substr($event,12,4);<br />
$unit = '°C';<br />
} <br />
<br />
return ($reading, $value, $unit);<br />
}<br />
</pre><br />
<br />
=== X_Shutdown ===<br />
Mit der X_Shutdown Funktion kann ein Modul bei einem Shutdown von FHEM die geöffneten Ressourcen schließen.<br><br />
Eingangsparameter: Der $hash einer Modul-Instanz<br><br />
<br />
Beispiel:<br />
<pre><br />
sub X_Shutdown($)<br />
{<br />
my ($hash) = @_;<br />
<br />
DevIo_CloseDev($hash);<br />
return undef;<br />
}<br />
</pre><br />
<br />
== Pollen von Geräten ==<br />
Wenn Geräte von sich aus keine Informationen senden sondern abgefragt werden müssen, kann man im Modul die Funktion <code>InternalTimer</code> verwenden. Man übergibt ihr den Zeitpunkt für den nächsten Aufruf, den Namen der Funktion, die aufgerufen werden soll, den zu übergebenden Parameter und ein Flag ob der erste Aufruf verzögert werden soll falls die Initialiserung des Geräts noch nicht abgeschlossen ist. Als zu übergebender Parameter wird üblicherweise der Hash der betroffenen Geräteinstanz verwendet. Damit hat die aufgerufene Funktion Zugriff auf alle wichtigen Daten der Geräteinstanz. Eventuell zusätzlich benötigte Werte können einfach als weitere Internals über den Hash zugänglich gemacht werden.<br />
<br />
Beispielsweise könnte man für das Abfragen eines Geräts in der Define-Funktion den Timer folgendermassen setzen:<br />
<br />
<pre><br />
# initial request after 2 secs, there timer is set to interval for further update<br />
InternalTimer(gettimeofday()+2, "X_GetUpdate", $hash, 0); <br />
</pre><br />
<br />
in der Funktion <code>X_GetUpdate</code> selbst wird dann der Timer neu gesetzt, so dass nach einem Intervall die Funktion erneut aufgerufen wird:<br />
<br />
<pre><br />
sub X_GetUpdate($)<br />
{<br />
my ($hash) = @_;<br />
my $name = $hash->{NAME};<br />
InternalTimer(gettimeofday()+$hash->{Interval}, "X_GetUpdate", $hash, 1);<br />
Log3 $name, 4, "X: GetUpdate called ...";<br />
</pre><br />
<br />
Im weiteren Verlauf der Funktion könnte man dann das Gerät abfragen und die abgefragten Werte in Readings speichern. Falls das Abfragen der Werte jedoch zu einer Verzögerung und damit zu einer Blockade von FHEM führen kann, ist es möglich, in der GetUpdate-Funktion nur die Aufforderung zum Senden bestimmter Daten an das angeschlossene Gerät zu senden und dann das Lesen über die oben beschriebene Read-Funktion zu implementieren, die beim Anstehen von Daten aufgerufen wird.<br />
<br />
== Logging / Debugging ==<br />
Um Innerhalb eines Moduls eine Protokollmeldung in die Fhem-Logdatei zu schreiben, wird die Funktion Log3 aufgerufen:<br />
<pre><br />
Log3 $name, 3, "X: Problem erkannt ...";<br />
</pre><br />
<br />
Die Parameter der Funktion Log3 sind der Name oder der Hash der Geräteinstanz, das Verbose-Level, in dem die Meldung sichtbar sein soll und die Meldung selbst.<br />
Den Namen der Geräteinstanz kann man in den Funktionen, die den Hash übergeben bekommen einfach aus diesem Hash nehmen:<br />
<br />
<pre><br />
my $name = $hash->{NAME};<br />
</pre><br />
<br />
Um für ein neues Modul das Verbose-Level zu erhöhen, ohne gleich für das Gesamte FHEM alle Meldungen zu erzeugen kann man den Befehl <br />
<code>attr gerätename verbose</code> verwenden. Beispielsweise <code>attr PM verbose 5</code><br />
<br />
Damit bietet es sich an im Modul Meldungen, die im normalen Betrieb nicht benötigt werden, beim Aufruf von Log3 mit dem Level 4 oder 5 anzugeben. Wenn man dann bei der Fehlersuche mehr Meldungen sehen möchte, erhöht man mit attr X verbose das Level für das betroffene Gerät.<br />
<br />
<br />
== Zweistufiges Modell für Module ==<br />
<br />
siehe auch<br />
* [http://forum.fhem.de/index.php/topic,18920.msg128100.html#msg128100|The FHEM two-level model]<br />
* [http://forum.fhem.de/index.php/topic,13438.msg83643.html#msg83643|Zum Initialize bei physikalischen und logischen Geräten]<br />
<br />
Das zweistufige Modell besteht aus <br />
* physisches Modul - z.B. für CUL (00_CUL.pm), der mehrer Protokolle empfängt, u.a. FS20<br />
* logische Modul(e) - z.B. das Protokoll FS20 (10_FS20.pm)<br />
<br />
Das physische Modul öffnet die Datenverbindung zum Gerät. <br />
<br />
=== Kommunikation vom Gerät zu den logischen Modulen ===<br />
{{Anker|KommunikationvomGerätZuLogischenModulen}}<br />
Die [[#X_Read|X_Read]]-Funktion wird aus der Hauptschleife von Fhem aufgerufen sobald das Gerät, für das das Modul zuständig ist, Daten bereit gestellt hat, die gelesen werden können.<br />
<br />
Unter Windows funktioniert "select" nur für Geräte, die via TCP verbunden sind. Für alle anderen Geräte ist eine [[#X_Ready|X_Ready]]-Funktion von Nöten, die 10x pro Sekunde das Gerät abfrägt und "true" zurück gibt, sollten Daten bereit stehen.<br />
<br />
Die X_Read-Funktion stellt sicher, dass die Daten<br />
* komplett und<br />
* korrekt<br />
sind und sie ruft die globale Funktion Dispatch() mit einer Nachricht auf.<br />
<br />
Dispatch() sucht nach einem passenden lokalen Modul via <br />
* $hash->{Clients} oder $hash->{MatchList} im physischen Modul<br />
* $hash->{Match} in allen passenden logischen Modulen<br />
und ruft X_Parse in den gefundenen Modulen auf.<br />
<br />
X_Parse <br />
* untersucht die übergebenen Daten (von Dispatch() übergeben)<br />
* setzt alle [[#Readings|readings]] via readings*update Funktionen<br />
* gibt den Namen des logischen Device zurück<br />
<br />
Es findet kein Event-Triggering statt, wenn die readings*update Funktionen <br />
* von X_Parse aufgerufen werden und<br />
* X_Parse wiederum von Dispatch() aufgerufen wurde.<br />
(Im Gegensatz zum direkten Aufrufen der readings*update Funktionen ohne vorhergehendes Dispatch() )<br />
<br />
Dispatch() triggert das Event-Handling für das von X_Parse zurückgegebene logische Device.<br />
<br />
=== Kommunikation von den logischen Modulen zum Gerät ===<br />
<br />
Um von einem logischen Modul an ein physisches Gerät zu senden, wird im logischen Modul das Attribut IODev mit dem namen des physischen Devices gesetzt.<br />
Der Befehl<br />
<code>AssignIoPort($hash);</code><br />
in der X_Define-Funktion des logischen Devices erledigt das.<br />
<br />
Als Befehl zum Schreiben vom logischen ins physische Gerät soll <code>IOWrite()</code> verwendet werden. IOWrite() ruft im physischen Gerät die X_Write-Funktion auf.<br />
<br />
Wenn es keine direkte Kommunikation zwischen dem logischen und dem physischen Gerät gibt(keine direkten Aufrufe von Funktionen, kein direktes überprüfen von $hash Werten,...) so können die Module hintereinander geschaltet werden (z.B. für Routerfunktionen wie in RFR) oder mittels FHEM2FHEM:RAW zwei Fhem Installationen verbunden werden und die logischen Devices werden dennoch funktionieren.<br />
<br />
== Ergänzende Hinweise ==<br />
Die Wahl der vorangestellten Nummer für den Dateinamen eines neuen Moduls hat keine Bedeutung mehr, es sei denn die Nummer ist 99. Module, die mit 99_ beginnen, werden von FHEM automatisch geladen. Module mit einer anderen Nummer nur wenn ein <code>define</code>-Befehl dafür sorgt, dass das Modul geladen wird.<br />
<br />
Wenn ein Modul Initialisierungsdaten benötigt, sollten diese im Modul selbst enthalten sein. Eine zusätzliche Datei oder sogar ein Unterverzeichnis mit mehreren Dateien ist bei FHEM nicht üblich und sollte bei Modulen, die mit FHEM ausgeliefert werden nur in Rücksprache mit Rudolf König angelegt werden, da sie sonst bei einem Update nicht verteilt werden.<br />
<br />
== Weitere Informationen ==<br />
Wenn man weitere Details wissen möchte, ist ein erster sinnvoller Schritt ein Blick in die Datei fhem.pl. Dort sieht man im Perl-Code wie die Module aufgerufen werden, was vorher passiert und was danach. Am Anfang der Datei (ca. ab Zeile 130) findet man beispielsweise eine Liste der globalen Variablen, die den Modulen zur Verfügung stehen sowie Details zu den wichtigen Hashes %modules und %defs. Wer mit Perl noch nicht so gut klar kommt, dem hilft eventuell ein Blick auf die Perldoc Website[http://perldoc.perl.org/] oder in das Perl-Buch seiner Wahl. Auch die FHEM Commandref [http://fhem.de/commandref.html] sollte nicht unterschätzt werden. Es stehen oft mehr interessante Details auch für Modulentwickler darin als man zunächst vermuten könnte.<br />
<br />
<br />
== "Hello World" Beispiel ==<br />
<br />
98_Hello.pm<br />
<br />
<pre><br />
package main;<br />
use strict;<br />
use warnings;<br />
<br />
my %Hello_gets = (<br />
"whatyouwant" => "can't",<br />
"whatyouneed" => "try sometimes",<br />
"satisfaction" => "no"<br />
);<br />
<br />
sub Hello_Initialize($) {<br />
my ($hash) = @_;<br />
<br />
$hash->{DefFn} = 'Hello_Define';<br />
$hash->{UndefFn} = 'Hello_Undef';<br />
$hash->{SetFn} = 'Hello_Set';<br />
$hash->{GetFn} = 'Hello_Get';<br />
$hash->{AttrFn} = 'Hello_Attr';<br />
$hash->{ReadFn} = 'Hello_Read';<br />
<br />
$hash->{AttrList} =<br />
"formal:yes,no "<br />
. $readingFnAttributes;<br />
}<br />
<br />
sub Hello_Define($$) {<br />
my ($hash, $def) = @_;<br />
my @param = split('[ \t]+', $def);<br />
<br />
if(int(@param) < 3) {<br />
return "too few parameters: define <name> Hello <greet>";<br />
}<br />
<br />
my $hash->{name} = $param[0];<br />
my $hash->{greet} = $param[2];<br />
<br />
return undef;<br />
}<br />
<br />
sub Hello_Undef($$) {<br />
my ($hash, $arg) = @_; <br />
# nothing to do<br />
return undef;<br />
}<br />
<br />
sub Hello_Get($@) {<br />
my ($hash, @param) = @_;<br />
<br />
return '"get Hello" needs at least one argument' if (int(@param) < 2);<br />
<br />
my $name = shift @param;<br />
my $opt = shift @param;<br />
if(!$Hello_gets{$opt}) {<br />
my @cList = keys %Hello_gets;<br />
return "Unknown argument $opt, choose one of " . join(" ", @cList);<br />
}<br />
<br />
if($attr{$name}{formal} eq 'yes') {<br />
return $Hello_gets{$opt}.', sir';<br />
}<br />
return $Hello_gets{$opt};<br />
}<br />
<br />
sub Hello_Set($@) {<br />
my ($hash, @param) = @_;<br />
<br />
return '"set Hello" needs at least one argument' if (int(@param) < 2);<br />
<br />
my $name = shift @param;<br />
my $opt = shift @param;<br />
my $value = join("", @param);<br />
<br />
if(!defined($Hello_gets{$opt})) {<br />
my @cList = keys %Hello_gets;<br />
return "Unknown argument $opt, choose one of " . join(" ", @cList);<br />
}<br />
$hash->{STATE} = $Hello_gets{$opt} = $value;<br />
<br />
return "$opt set to $value. Try to get it.";<br />
}<br />
<br />
<br />
sub Hello_Attr(@) {<br />
my ($cmd,$name,$attr_name,$attr_value) = @_;<br />
if($cmd eq "set") {<br />
if($attr_name eq "formal") {<br />
if($attr_value !~ /^yes|no$/) {<br />
my $err = "Invalid argument $attr_value to $attr_name. Must be yes or no.";<br />
Log 3, "Hello: ".$err;<br />
return $err;<br />
}<br />
} else {<br />
return "Unknown attr $attr_name";<br />
}<br />
}<br />
return undef;<br />
}<br />
<br />
1;<br />
<br />
=pod<br />
=begin html<br />
<br />
<a name="Hello"></a><br />
<h3>Hello</h3><br />
<ul><br />
<i>Hello</i> implements the classical "Hello World" as a starting point for module development. <br />
You may want to copy 98_Hello.pm to start implementing a module of your very own. See <br />
<a href="http://www.fhemwiki.de/wiki/DevelopmentModuleIntro">DevelopmentModuleIntro</a> for an <br />
in-depth instruction to your first module.<br />
<br><br><br />
<a name="Hellodefine"></a><br />
<b>Define</b><br />
<ul><br />
<code>define &lt;name&gt; Hello &lt;greet&gt;</code><br />
<br><br><br />
Example: <code>define HELLO Hello TurnUrRadioOn</code><br />
<br><br><br />
The "greet" parameter has no further meaning, it just demonstrates<br />
how to set a so called "Internal" value. See <a href="http://fhem.de/commandref.html#define">commandref#define</a> <br />
for more info about the define command.<br />
</ul><br />
<br><br />
<br />
<a name="Helloset"></a><br />
<b>Set</b><br><br />
<ul><br />
<code>set &lt;name&gt; &lt;option&gt; &lt;value&gt;</code><br />
<br><br><br />
You can <i>set</i> any value to any of the following options. They're just there to <br />
<i>get</i> them. See <a href="http://fhem.de/commandref.html#set">commandref#set</a> <br />
for more info about the set command.<br />
<br><br><br />
Options:<br />
<ul><br />
<li><i>satisfaction</i><br><br />
Defaults to "no"</li><br />
<li><i>whatyouwant</i><br><br />
Defaults to "can't"</li><br />
<li><i>whatyouneed</i><br><br />
Defaults to "try sometimes"</li><br />
</ul><br />
</ul><br />
<br><br />
<br />
<a name="Helloget"></a><br />
<b>Get</b><br><br />
<ul><br />
<code>get &lt;name&gt; &lt;option&gt;</code><br />
<br><br><br />
You can <i>get</i> the value of any of the options described in <br />
<a href="#Helloset">paragraph "Set" above</a>. See <br />
<a href="http://fhem.de/commandref.html#get">commandref#get</a> for more info about <br />
the get command.<br />
</ul><br />
<br><br />
<br />
<a name="Helloattr"></a><br />
<b>Attributes</b><br />
<ul><br />
<code>attr &lt;name&gt; &lt;attribute&gt; &lt;value&gt;</code><br />
<br><br><br />
See <a href="http://fhem.de/commandref.html#attr">commandref#attr</a> for more info about <br />
the attr command.<br />
<br><br><br />
Attributes:<br />
<ul><br />
<li><i>formal</i> no|yes<br><br />
When you set formal to "yes", all output of <i>get</i> will be in a<br />
more formal language. Default is "no".<br />
</li><br />
</ul><br />
</ul><br />
</ul><br />
<br />
=end html<br />
<br />
=cut<br />
</pre><br />
<br />
Der HTML-Code zwischen den Tags <code>=pod</code> und <code>=cut</code> dient zur Generierung der commandref.html. Der HTML-Inhalt wird automatisch beim Verteilen des Moduls im Rahmen des Update-Mechanismus aus jedem Modul extrahiert und daraus die Commandref in verschiedenen Sprachen erstellt. Eine detaillierte Beschreibung wie ein Commandref-Abschnitt in einem Modul definiert wird, siehe: [[Guidelines zur Dokumentation]]<br />
<br />
== Noch zu beschreiben ==<br />
* Zweistufiges Modell für Module<br />
* Funktion X_State_Fn: {{Link2Forum|Topic=32680}}, siehe auch [[DevelopmentState]]<br />
* FW_summaryFn (wird von FHEMWEB aufgerufen fuer Raum-Uebersicht)<br />
* FW_detailFn (wird von FHEMWEB aufgerufen fuer Detail-Ansicht)<br />
* DevIO<br />
* AsyncOutputFn / asyncOutput<br />
* SetExtensions / SetExtensionsCancel<br />
* ExceptFn (gleiche wie ReadFn aber EXCEPT_FD anstelle von FD)<br />
* FingerprintFn<br />
* ParseFn<br />
<br />
[[Kategorie:Development]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Batterie%C3%BCberwachung&diff=16537Batterieüberwachung2016-10-06T09:30:51Z<p>Fabian: Überschriften-Level korrigiert</p>
<hr />
<div>Verschiedene batteriebetriebene Geräte ([[:Kategorie:HomeMatic Components|Homematic]],RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Bei diesen kann der Batteriestatus übersichtlich dargestellt u/o aktiv überwacht werden. Bei Geräten ohne eigenen Batteriestatus muss man diesen "nachrüsten".<br />
<br />
<br />
== Geräte mit Batteriestatus ==<br />
<br />
=== Übersichtsdarstellung per readingsGroup ===<br />
Mit Hilfe einer ReadingsGroup kann einfach eine Übersicht aller Geräte mit "battery"-Reading erstellt werden, s. [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|hier]].<br />
<br />
<br />
=== Benachrichtigung per notify ===<br />
Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME : Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
'''Achtung:''' Für Nutzer eines [[HM-CC-RT-DN_Funk-Heizk%C3%B6rperthermostat|HM-CC-RT-DN]] muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:<br />
<br />
UG.Treppe.Heizung batteryLevel: 3.1 V<br />
<br />
Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME: Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel [[E-Mail_senden]] beschrieben.<br />
<br />
Testen kann man dies z.B. mit <code>trigger HeizungWZ Battery:low</code><br />
<br />
Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut <code>event-on-change-reading</code>).<br />
<br />
<br />
<br />
== Geräte ohne Batteriestatus ==<br />
Bei Geräten ohne Reading für den Batteriestatus kann man diesen auf verschiedene Weisen schätzen und als Reading eintragen. Dies funktioniert aber natürlich nur, wenn das Gerät sendet - bei einem rein empfangenden Aktor wie dem [[FHT 8v direkt ansprechen|FHT Stellantrieb]] klappt es also nicht... <br />
<br />
=== Erweiterung des Geräts um battery-Reading ===<br />
Mit Hilfe von [http://fhem.de/commandref_DE.html#userReadings userReadings] kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.<br />
<br />
Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.<br />
<br />
Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen): <br />
<br />
; Konfiguration:<br />
Lediglich der Schwellwert (600) braucht nach Wunsch angepasst zu werden, alles andere passt automatisch (vgl. [http://www.fhemwiki.de/wiki/Notify#Hinweise]).<br />
<br />
; Im Webinterface:<br />
<pre><br />
battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }<br />
</pre><br />
<br />
; Alternativ im Config-File:<br />
<pre><br />
attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>$NAME</code> - ist die Variable für das Device (und braucht nicht angepasst zu werden)<br />
: <code>battery {...}</code> - Name des userreadings mit Spezifikation, vgl. [http://fhem.de/commandref_DE.html#userReadings]<br />
: <code>return "ok" if ( ... );; return "low"</code> - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"<br />
: <code>time_str2num(ReadingsTimestamp($NAME,"state","0")</code> - Aktueller Timestamp in Sekunden, vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>time_str2num(OldTimestamp($NAME))</code> - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>600</code> - Schwellwert für "low" (600 sec = 10 min), nach Bedarf anpassen<br />
<br />
<br />
=== Alternativ per Skript ===<br />
<br />
Andere Komponenten, wie z. B. [[:Kategorie:FS20 Components|FS20 Komponenten]], übermitteln keinen Batteriestatus. <br />
<br />
Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in [[99_myUtils_anlegen|99_myUtils.pm]]:<br />
<br />
<pre>sub check_if_alive($$) {<br />
# Expects:<br />
# 1. Devicename to be checked<br />
# 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.<br />
# Returns:<br />
# 0 -> Device dead<br />
# 1 -> Device alive<br />
# 2 -> Error<br />
my ($Device,$hours_threshold) = @_;<br />
my ($Device) = @_;<br />
my $now = time;<br />
my $Timestamp = ReadingsTimestamp($Device,"state","0");<br />
if ($Timestamp eq "0") {<br />
return 2;<br />
}<br />
<br />
my @splitdatetime = split(/ /,$Timestamp);<br />
my @splitdate = split(/-/, $splitdatetime[0]);<br />
my @splittime = split(/:/, $splitdatetime[1]);<br />
my $last_state_time = timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);<br />
my $age_in_hours = ($now - $last_state_time) / 3600;<br />
<br />
if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
return 0;<br />
} else {<br />
return 1;<br />
}<br />
<br />
}</pre><br />
<br />
Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:<br />
<br />
<pre>*05:55:55 { <br />
check_if_alive("KS300", 12);<br />
}</pre><br />
<br />
KS300 ist dabei der Name des Devices in fhem. <br />
<br />
Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.<br />
<br />
Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.<br />
<br />
==== Visualisierung ====<br />
<br />
Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.<br />
<br />
Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:<br />
<br />
<pre>Internals: <br />
NAME dum_KS300_dead <br />
NR 795 <br />
STATE nein <br />
TYPE dummy <br />
Readings: <br />
2015-04-28 07:47:48 state nein <br />
Attributes: <br />
devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green</pre><br />
<br />
Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie. <br />
<br />
Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:<br />
<br />
<pre> if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
fhem("set dum_".$Device."_dead ja");<br />
return 0;<br />
} else {<br />
fhem("set dum_".$Device."_dead nein");<br />
return 1;<br />
}</pre><br />
<br />
Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.<br />
<br />
== Links ==<br />
<br />
* [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|visuelle Batterieüberwachung mit readingsGroup]]<br />
* [http://fhem.de/commandref_DE.html#userReadings commandref - userReadings]<br />
* [http://fhem.de/commandref_DE.html#perl commandref - Perl specials]<br />
* [[Notify#Hinweise|Hinweise zu Variablen]] (ansonsten auch an div. Stellen in der [http://fhem.de/commandref_DE.html commandref])<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Hardware]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Trick_der_Woche&diff=16536Trick der Woche2016-10-06T09:27:45Z<p>Fabian: Verweis zu Batterieüberwachung gesetzt</p>
<hr />
<div>Diese Seite enthält Tipps und Tricks, die zu unbedeutend sind, einen eigenen Artikel zu rechtfertigen, alternative Schreibweisen/Lösungen für eine Problem darstellen, Ungenauigkeiten oder unklare Formulierungen in den offiziellen Dokumenten ergänzen und ähnliches. Jeder Eintrag ist typischerweise sehr kurz (wenige Zeilen lang) und beleuchtet vielleicht nur einen Aspekt von Fhem, er kann allgemeiner Natur sein, oder sich auf ein spezielles Gerät oder einen speziellen Anwendungsfall beziehen.<br />
<br />
<br />
<br />
== Oktober 2016 ==<br />
<br />
=== Grundlagen der Heizungssteuerung ===<br />
Der Artikel [[Grundlagen der Heizungssteuerung]] soll einen zentralen Einstiegspunkt und eine Übersicht der Möglichkeiten insb. für Neulinge in FHEM bieten.<br />
<br />
=== Batterieüberwachung für Geräte ohne Batteriestatus ===<br />
Es gibt Möglichkeiten um auch bei Geräten ohne Batteriestatus-Reading eine schwache Batterie erkennen zu können: [[http://www.fhemwiki.de/wiki/Batterie%C3%BCberwachung#Ger.C3.A4te_ohne_Batteriestatus]]. <br />
<br />
<br />
== Mai 2016 ==<br />
=== DbLog reparieren ===<br />
Sollte ein fhem mit DbLog Probleme machen, oder auf der SQL-Konsole Fehler werfen, so ist eine Reparatur der DB fällig. Das ist auf der Kommandozeile verhältnismäßig einfach möglich und wird im Kapitel [[DbLog#Datenbank reparieren]] beschrieben.<br />
<br />
=== DbLog bearbeiten ===<br />
Unerwünschte Einträge in den Loggings treten immer wieder mal auf. Wie man dies in einer Datenbank korrigiert, dazu gibt das Kapitel [[DbLog#Bearbeitung von Datenbank-Einträgen]] eine erste Einführung.<br />
<br />
=== Pollenflug ===<br />
In dieser schönen Jahreszeit werden manche durch Heuschnupfen geplagt. Auf der Seite [[Pollenflug]] wird beschrieben, wie man eine Pollenvorhersage in fhem einbinden kann - hilft zwar nicht gegen das Niesen, ist aber trotzdem ganz informativ... ;-)<br />
<br />
== April 2016 ==<br />
=== HomeMatic und VCCU ===<br />
HomeMatic Nutzer sollten unbedingt eine [[Virtueller Controller VCCU|VCCU]] einrichten und nutzen.<br />
Die Einrichtung ist unaufwändig und schafft jede Menge Vorteile, auch beim Einsetzen nur einer Schnittstelle wie z.B. einem [[HM-CFG-LAN LAN Konfigurations-Adapter]]. Auch die nachträglich Einrichtung ist problemlos, sofern vorher nur ein I/O Gerät ("Funkschnittstelle") verwendet wurde.<br />
<br />
== Dezember 2015 ==<br />
===defmod===<br />
In vielen Fällen will man mit einer Aktion gleichzeitig eine andere Aktion bereits für später festlegen, z.b. nach Einschalten einer Heizung durch einen Bewegungsmelder diese eine Stunde später wieder ausschalten.<br />
<br />
Dies kann z.B. durch ein Konstrukt dieser Art erledigt werden:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; define reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
<br />
Nachteilig ist, dass bei einer weiteren Auslösung des Bewegungsmelders die Heizzeit nicht verlängert wird, da eine Neudefinition von '''reset_Heizung''' mit der Fehlermeldung '''reset_Heizung already exists, delete it first''' quittiert wird. Die Lösung bisher war, das alte '''reset_Heizung''' zunächst zu löschen und dann erneut mit neuem Zeitstempel anzulegen:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; delete reset_Heizung ;; define reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
Aber auch dieses umständliche Konstrukt hat noch einen Nachteil: Es erzeugt bei einer ersten Auslösung eine Fehlermeldung, weil '''reset_Heizung''' noch nicht exisitert und daher nicht gelöscht werden kann. Dies liesse sich abfangen, was die Konstruktion weiter verkomplizieren würde.<br />
<br />
Daher hat Rudolf König mit FHEM 5.6 den neuen Befehel "defmod" eingeführt, der ein noch nicht existieredendes define neu anlegt (wie "define"), eine bereits vorhandenes aber direkt ändert (wie "delete" und danach "define")<br />
<br />
Dadurch lässt sich verkürzt schreiben:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; defmod reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
<br />
<br />
<br />
== April 2015 ==<br />
===FS20 Timer===<br />
FS20 Aktoren beherrschen zwei verschiedene Timer-Methoden.<br />
<br />
Angenommen ein FS20 Device heisse "Lampe" und sei z.B. ein [[FS20_SU_Unterputz-Funk-Schalter|FS20 SU]] (Unterputzschalter), dann kann man mit FHEM sowohl <br />
:<code> set Lampe on-for-timer 30</code><br />
verwenden um die Lampe 30 Sekunden einzuschalten, aber auch zunächst in den FS20 SU die maximale Einschaltdauer einprogrammieren:<br />
:<code> set Lampe timer 30</code><br />
Dannach wird jedes normale<br />
:<code> set Lampe on</code><br />
die Lampe für nur 30 Sekunden einschalten.<br />
<br />
Als Timerwerte kommen in beiden Fällen die bekannten [[Trick_der_Woche#FS20_Timerzeiten|128 Sekundenwerte]] von 0,25 Sekunden bis Etwa 4,5 Stunden in Frage.<br />
<br />
Es ist offenbar nicht bei allen Aktoren möglich einen einmal eingestellten Timer zu löschen, neue Werte eingeben aber sehr wohl.<br />
<br />
Mehr hier: [[FS20_Allgemein#Gerätetimer setzen / löschen|FS20 timer]].<br />
<br />
== Februar 2015 ==<br />
=== 1-wire am GPIO4-Port des RaspberryPi funktioniert nicht mehr nach Systemupdate ===<br />
Es kann passieren, dass nach einem Systemupdate (apt-get update oder apt-get dist-upgrade) die 1-wire-Geräte am GPIO4-Port plötzlich nicht mehr funktionieren. Eine Problemlösung dazu ist im Artikel "[[Raspberry Pi und 1-Wire#1-wire am GPIO4-Port funktioniert nicht mehr nach Systemupdate]]" beschrieben.<br />
<br />
=== Backup der Konfiguration (fhem.cfg und fhem.state) bei jedem "save" ===<br />
Der nachfolgende Codeschnipsel erstellt bei jedem "save" eine Kopie der aktuellen [[Konfiguration]] (fhem.cfg und fhem.state) in ein Verzeichnis "backup_cfg-state" welches unter /opt/fhem/ zu finden ist. Somit kann bei einem Fehler jederzeit auf den letzten Stand zurückgegangen werden.<br />
Zuerst ins FHEM Befehlsfeld den folgenden Befehl eingeben:<br />
:<code>{ `mkdir backup_cfg-state` } </code><br />
<br />
Danach folgendes [[notify]] anlegen:<br />
define backupCfg notify global:SAVE {\<br />
my $now = TimeNow();; $now =~ s/ /_/g;; \<br />
`cp $attr{global}{configfile} ./backup_cfg-state/fhem.cfg.$now`;;\<br />
`cp $attr{global}{statefile} ./backup_cfg-state/fhem.state.$now`;;\<br />
} <br />
<br />
Quelle: {{Link2Forum|Topic=30873|Message=234412|LinkText=FHEM-Forum}}<br />
<br />
== Januar 2015 ==<br />
=== CUL & CO über Serial ID-einbinden ===<br />
Bei mehreren USB-Geräten kann es vorkommen, dass sie vertauscht werden z.B. ''/dev/ttyUSB0'' zu'' /dev/ttyUSB1'' oder ''/dev/ttyACM0'' zu ''/dev/ttyACM1''.<br />
<br />
Um dies zu umgehen, kann man sie über ihre Serial-ID in Fhem einbinden.<br />
<br />
Dieser Befehl zeigt die Serial-ID:<br />
<br />
:<code>ls -l /dev/serial/by-id</code><br />
<br />
Hier die Beispielausgabe eines CUL868, JeeLink, RFXtrx und eines CUL433<br />
<br />
user@xxxx:~# ls -l /dev/serial/by-id<br />
lrwxrwxrwx 1 root root 13 Jan 9 23:34 usb-busware.de_CUL868-if00 -> ../../ttyACM0<br />
lrwxrwxrwx 1 root root 13 Jan 9 13:26 usb-FTDI_FT232R_USB_UART_A901RQ9F-if00-port0-> ../../ttyUSB0<br />
lrwxrwxrwx 1 root root 13 Jan 9 13:26 usb-RFXCOM_RFXtrx433_A1WZWL5Y-if00-port0-> ../../ttyUSB1<br />
lrwxrwxrwx 1 root root 13 Jan 9 21:29 usb-busware.de_CUL433-if00 -> ../../ttyACM1 <br />
<br />
Damit lässt sich folgende Definition erstellen:<br />
<br />
z.B. für einen CUL868<br />
<br />
:<code>define CUL868 CUL /dev/serial/by-id/usb-busware.de_CUL868-if00@9600 1134</code><br />
<br />
oder einen JeeLink<br />
<br />
:<code>define Jeelink JeeLink /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A901RQ9F-if00-port0@57600</code><br />
<br />
'''Einschränkung:''' Bei CULs von Busware lassen sich nur CUL433 und CUL868 unterscheiden. Zwei CUL868 haben z.B. immer die gleiche Serial-ID.<br />
<br />
=== HM LAN Konfig-Adapter Antenne verbessern===<br />
Die Antenne des [[HM-CFG-LAN LAN Konfigurations-Adapter]] kann man mit etwas Bastelgeschick verlängern um den Empfang zu verbessern. <br />
<br />
Sinnvoll ist die Verlängerung auf 1/2 Lambda (868MHz = 17,27 cm) oder gar 1 Lambda.<br />
1 Lambda Antennen haben starke Richtwirkung in Form eines gedachten Zylinders, dessen Mittelachse die Antenne ist.<br />
D.h., Alles was sich in Richtung des Anfangs und des Endes des Antennedrahtes befindet, hat schlechteren Empfang als mit einer kurzen Antenne. Daher muss man die Antenne ggf. genauer ausrichten.<br />
<br />
Anleitungen dazu werden an verschiedenen Stellen veröffentlicht, z.B. in <br />
[http://www.ip-symcon.de/forum/threads/18411-Umbau-HM-LAN-Adapter-auf-Lambda-1-2-Dipol-Antenne diesem Beitrag] im IP-Symcon Forum (anders als der Namen der Anleitung vermuten lässt, liegt hier kein Dipol vor, sondern eine "normale" 1 Lambda Antenne.)<br />
<br />
Prinzipiell so dünnen Draht wie möglich verwenden.<br />
<br />
Wer noch mehr rausholen will, kann auch zusätzlichen Aufwand betreiben und die Antenne etwas von der Elektronik entfernen, die nämlich Störstrahlung in die Antenne einkoppelt. Oder eine Groundplane bauen.<br />
Ein Anleitung für die CCU (analog auch für den HM LAN Konfig-Adapter einsetzbar) gibt es [http://www.techwriter.de/beispiel/funkeige.htm hier].<br />
<br />
== Dezember 2014 ==<br />
=== FHT80TF als "Prüfsender" einsetzen ===<br />
Da der [[FHT80TF-2]] günstig ist und seinen Zustand ca. alle zwei Minuten sendet, kann er gut zum Ermitteln der Funklage von [[SlowRF]] Komponenten genutzt werden, auch wenn diese nicht senden. Den RSSI einer FS20 Schaltsteckdose kann man z.B. nicht wissen, da die Dose nur ein Empfänger ist. Wenn eine Dose nicht gut funktioniert und man den Verdacht hat, dass sie funktechnisch ungünstig liegt, kann man einen [[FHT80TF-2]] neben die Steckdose legen und man bekommt nach zwei Minuten einen Wert, der (trotz umgekehrter Funkrichtung) gut genug ist, um einem Hinweise zu geben.<br />
<br />
<br />
== November 2014 ==<br />
=== FS20 Adressschema und die Rolle des Hauscodes ===<br />
[[FS20_Allgemein#FS20_Adressierungsschema_.28Vorschlag.29]]<br />
<br />
<br />
== Oktober 2014 ==<br />
=== Aktor für Wanddosen ohne Nulleiter ===<br />
Zwar gibt es viele Aktoren, die man in Wanddosen hinter Schaltern einbauen kann, oft scheitert deren Nutzung aber daran, dass in vielen Elektroinstalltionen in der Wanddose eines (Licht)schalters kein Nulleiter verlegt ist, den die meisten Aktoren zur eigenen Stromversorgung brauchen. Hier kann der [[RSL 2-Draht Einbauschalter]] helfen, der auch ohne Nulleiter funktioniert und kompatibel zu InterTechno ist. Er lässt sich z.B. mit einem CUL(433) schalten. Problematisch ist allerdings das Schalten von LED Lampen.<br />
<br />
<br />
<br />
== August 2014 ==<br />
=== Perl-Skripte Online testen ===<br />
Im Internet existieren Webseiten auf denen man Perl-Code online testen kann. Beispielsweise auf [http://www.tutorialspoint.com/execute_perl_online.php codingground] kann man Code zum Testen eingeben und die Auswirkungen betrachten. Dies eignet sich zur schnellen Fehleranalyse oder um Perl zu lernen. Natürlich lassen sich keine Fhem-Besonderheiten nutzen.<br />
<br />
== Juli 2014 ==<br />
=== Funklast reduzieren===<br />
Bewegungsmelder erzeugen in der Regel eine recht hohe Funklast, wenn sie oft ausgelöst werden, also z.B. Licht in einem Zimmer schalten sollen.<br />
<br />
Konstruktionen der Art:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* set Licht_Flur on-for-timer 256</code><br />
haben daher den Nachteil bei viel Bewegung im Flur und je nach Einstellung des Sendeabstandes des Bewegungsmelders mindestens alle 120 Sekunde oder öfter ein <br />
:<code>on-for-timer 256</code><br />
zu senden. Das erzeugt eine hohe Funklast, speziell wenn der Aktor ein SlowRF Gerät ist (z.B. FS20 Unterputzschalter).<br />
In solchen Fällen kann es helfen, nur dann einen Befehl zu senden, wenn das Licht nicht schon an ist:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* { if (Value("Licht_Flur") eq "off") { fhem ("set Licht_Flur1 on-for-timer 256") } }</code><br />
Nachteilig ist aber, dass eine Auslösung innerhalb 256 Sekunden die Einschaltzeit nicht verlängert. Dies kann man umgehen, indem man nicht on-for-timer verwendet, sondern den Aktor selber verzögert auschaltet und bei weiteren Auslösungen nur die Verzögerung erneut anlegt:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* { if (Value("Licht_Flur1") eq "off") { fhem ("set Licht_Flur on ;; define FlurLicht_aus at +00:04:16 set Licht_Flur off") } else { fhem ("delete FlurLicht_aus ;; define FlurLicht_aus at +00:04:16 set Licht_Flur off") }}</code><br />
Durch den relativ neuen Befehl "defmod" kann ausserdem das Löschen und neu Anlegen zusammengefasst werden, sieh Tipp Dezember 2015<br />
<br />
== Juni 2014 ==<br />
=== Batteriestatus bei HomeMatic Devices aktivieren===<br />
Zumindest einige (wenn nicht alle) batteriegespeisten HM-Geräte können Batteriemeldungen senden, tun dies in der normalen Konfiguration aber nicht.<br />
Dazu muss das Register cyclicInfoMsg auf on gesetzt werden. <br />
<br />
Wie man das macht steht z.B. hier<br />
[[HM-SEC-SC_Tür-Fensterkontakt#Batteriestatus_aktivieren]]<br />
und hier<br />
[[HomeMatic_Type_ThreeState]]<br />
<br />
== Mai 2014 ==<br />
=== Dummywert mit aktueller Uhrzeit versehen in anderen Dummy kopieren===<br />
Der Inhalt von Dummy1 soll erweitert um Uhrzeit und Datum in Dummy2 kopiert werden (z.B. um die Urzeit der letzten Auslösung einer Alarmanlage anzuzeigen)<br />
:<code>{ fhem("set dummy2 " . (Value("Dummy1")." ".TimeNow()) ) } </code><br />
<br />
=== Zwei Dummywerte in einen anderen Dummy kopieren ===<br />
Der String in Dummy1 soll um den String in Dummy2 erweitert und nach Dummy3 kopiert werden:<br />
:<code>{ fhem("set Dummy3 ".(Value("Dummy1")+Value("Dummy2"))) } </code><br />
(Achtung: "+" ist Zahlen addieren, "." ist String konkatenieren) <br />
<br />
== April 2014==<br />
=== Code sparen ===<br />
Wer Definitionen wie die aus dem März zum [[Trick der Woche#Zuverlässigkeit von FS20 Schaltungen erhöhen|Abfangen von Fehlbedienungen]] verwendet, kann durch eine ELSE Erweiterung auch gleich das Auschalten erledigen.<br />
:<code>define act_on_TV_on notify TV { if ("$EVENT" eq "on" || "$EVENT" eq "dimup") { fhem("set TV on") } else { fhem("set TV off") } }</code><br />
<br />
Hierdurch schaltet ON oder versehentlich zu langes Drücken (also DIMUP) den Fernseher ein, jeder ''andere'' Tastendruck (also insbesondere die OFF Taste oder zu langes Drücken der OFF Taste -> DIMDOWN) den Fernseher aus.<br />
<br />
Voraussetzung ist, dass die Fernbedienung standardkonfiguriert ist, siehe auch nächster Tip.<br />
<br />
=== Konfiguration eines FS20 Senders prüfen ===<br />
Gelegentlich reagieren bestimmte notifys nicht, die von Sendern (Fernbedienungen, Sensoren oder Schaltern) ausgelöst werden sollen. Speziell bei FS20 aber auch bei HomeMatic kann das daran liegen, dass der Sender nicht sendet was man denkt. So gut wie alle FS20 Sender kennen nämlich nicht nur ON und OFF, sondern über ein Dutzend Schaltzustände. Dimmen ist einem noch hinreichend bewusst, es gibt aber auch exotische Dinge wie Ein-für-Zeitdauer, Ein-auf-alte-Helligkeit, Aus-für-Zeitdauer (nur FS20), Ein-für-Zeitdauer-dannach-alter-Zustand und vieles mehr.<br />
<br />
Was also ein Infrarot-Bewegungsmelder bei Auslösung sendet und auch was eine Fernbedienungstaste sendet ist einstellbar. Wenn jetzt zum Beispiel an einer Fernbedienung auf Tastendruck nicht ON sondern Ein-für-Zeitdauer (ON-FOR-TIMER) gesendet wird, wird<br />
:<code>define act_on_TV_on notify TV:on set TV on</code><br />
seltsamerweise nicht auslösen, obwohl die richtige Taste (und diese auch nicht zu lang) gedrückt wurde.<br />
<br />
Auch wenn man sich sicher ist, das Richtige in die Fernbedienung/Sensoren einprogramiert zu haben, ist ein einfacher Test immer, dies mit<br />
:<code>define act_on_TV notify TV set TV on</code><br />
zu prüfen. Dieses notify löst immer aus, wenn "TV" ''irgendetwas'' sendet, egal was. (Beachte: Man kann dann den Fernseher aber nicht mehr ausschalten, da auch die Austaste das notify auslöst und zum TV-Aktor nur "on" sendet). Geht die Schaltung jetzt (kann man den Fernseher also jetzt EINschalten), liegt der Verdacht nahe, dass die Konfiguration des Senders / Sensors anders ist, als man denkt. Das Logfile gibt Aufschluss, welcher Befehl tatsächlich empfangen wurde.<br />
<br />
=== Alles in FHEM, nichts in der Fernbedienung ===<br />
Versuche in deiner FHEM Umgebung nicht, das Verhalten von Aktoren durch entsprechende Befehle aus Sensoren oder Fernbedienungen zu steuern. An Besten senden die nur ON und OFF oder DIM, den Rest möglichst immer in FHEM erledigen. <br />
<br />
Wer eine Lampe immer für vier Minuten einschalten will, programmiert seinen Schalter (Fernbedienung) also so, das nur "on" gesendet wird und erledigt den Rest in FHEM:<br />
:<code>define act_on_Schalter notify Schalter set Lampe-on-for-timer 240</code><br />
<br />
Vielfach wird argumentiert, das eine dirkete Kopplung die Zuverlässigkeit erhöht, da bei einem Ausfall von FHEM der Aktor totzdem schaltbar sei.<br />
Überlege, ob es hier nicht weniger komplex ist, die Zuverlässigkeit der FHEM Instanz zu erhöhen.<br />
<br />
== März 2014==<br />
=== Zuverlässigkeit von FS20 Schaltungen erhöhen ===<br />
FS20 Fernbedienungen senden bei Tastendrücken von mehr als 0,4 Sekunden anstatt ON bzw. OFF DIMUP bzw DIMDOWN.<br />
<br />
Das führt gelegentlich zu allgemein schlechter Bedienbarkeit (und schlechtem WAF), da 0,4 Sekunden relativ kurz ist und gerne aus versehen länger gedrückt wird. Das ist vor allem problematisch, wenn etwas geschaltet werden soll, was keinen Dimmer hat oder Dimmen nicht unterstützt.<br />
<br />
Eine Konfiguration wie <br />
:<code>define act_on_TV_on notify TV:on set TV on</code><br />
hat also dann den Nachteil, dass bei versehentlich zu langem Tastendruck das TV nicht angeht. Da die meisten Nutzer unbewusst dazu neigen, bei Misserfolg die selbe Taste erneut aber länger zu drücken (was erneut keinen Erfolg zeigt) ist Frustration zu erwarten.<br />
<br />
Es kann daher speziell bei nicht dimmbaren Aktoren von Vorteil sein, auch dimmen abzufangen, z.B. durch eine zweite zusätzliche Definition:<br />
<br />
:<code>define act_on_TV_dimup notify TV:dimup set TV on</code><br />
<br />
Es ist in der Regel einfacher, einige dieser zusätzlichen Definitionen einzufügen, als allen Bedienern des Systems zu erklären, dass man keinesfalls länger als 0,4 Sekunden drücken darf.<br />
<br />
Alternativ kann man auch beide Befehle in einer Definition durch Perlbefehle {} abfangen:<br />
<br />
:<code>define act_on_TV_on notify TV { if ("$EVENT" eq "on" || "$EVENT" eq "dimup") { fhem("set TV on") }}</code><br />
<br />
Andere Möglichkeiten vergleiche: [[Trick der Woche#notify durch mehrere Ereignisse auslösen lassen|Notify durch mehrere Ereignisse auslösen lassen]]<br />
<br />
== Februar 2014==<br />
=== Sequence nutzen ===<br />
Man kann Aktionen statt mit einem Tastedruck auch mit einer Sequenz von Tastendücken auslösen. Das Format des Befehle ist:<br />
<br />
:<code>define <name> sequence <re1> <timeout1> <re2> [<timeout2> <re3> ...] </code><br />
<br />
wobei <re1> ...<re_n> die Aktionen sind und <timeout_n> der maximale Abstand der Tastendrücke in Sekunden.<br />
<br />
Angenommen, man wolle z.B. eine Lampe dann anschalten, wenn man zuerst Taste1 EIN, dann Taste2 AUS und dann wieder Taste1 EIN einer Fernbedienung drückt, könnte das konkret so aussehen:<br />
<br />
:<code>define MeineLampenSequenz1 sequence Btn1:on 0.5 Btn2:off 0.5 Btn1:on</code><br />
<br />
Zwischen jedem der Tastendrücke darf eine halbe Sekunde Abstand sein. Diese Definition selbst löst die Lampe nicht aus, sondern definiert nur wie die Sequenz aussehen soll. Um die Lampe bei erfolgreicher Betätigung der Sequenz auch einzuschalten, bedarf es zusätzlich etwas wie:<br />
<br />
:<code>define MeineLampe notify MeineLampenSequenz1:trigger set Lampe on</code><br />
<br />
Sequence kann man gut nutzen, um mit einer Fernbedienung mehr Funktionen zu schalten als Tasten zur Verfügung stehen. Ebenso könnte man damit simple Codeschlösser für Alarmanlagen bauen, z.B. um eine Anlage auszuschalten, wenn eine bestimmte Abfolge von Tasten gedrückt wird.<br />
<br />
Je nach Funksystem nimmt die Zuverlässigkeit aber rasch ab. Angenommen im Bereich FS20 (das System ist etwas unzuverlässiger ist als z.B. HomeMatic) seien 95% aller Funktsignale ungestört übertragbar, dann würden in der Praxis von 100 Tastendrücken an einer Fernbedienung 95x Erfolg zeigen und 5x fehlschlagen; das ist sicher tolerabel. <br />
<br />
Bei einer Sequenzlänge von nur 4 Tasten würde die kombinierte Erfolgsquote der Sequenz jedoch nur noch ca. 80% sein, zum Ausschalten einer Alarmanlage vermutlich bereits unpraktisch.<br />
<br />
== Januar 2014==<br />
===isday===<br />
Bekanntlich kann man mit "isday" leicht testen ob es draussen hell ist oder nicht. isday ist eine Funktion des (automatisch geladenen) Moduls [[SUNRISE_EL]], das auch sunset und sunrise enthält.<br />
<br />
Problematisch bei isday ist die fehlende Möglichkeit, Sonnenaufgang und Untergang einzustellen (zumindest wenn man nicht 99_SUNRISE_EL.pm verändern will): isday ist wahr, wenn die Sonne im gegebenen Breitengrad sichtbar ist. Wenn örtliche Gegebenheiten eine Anpassung erfordern, kann man sich auch ein eigenes isday basteln, in dem man sunrise und sunset verwendet und dieses mit getrennten offsets versieht.<br />
<br />
Zuerst definiert man sich eine Variable ("dummy") der anstelle isday eingesetzt werden soll, z.B.:<br />
<br />
:<code>define Tageslicht dummy </code><br />
<br />
Dann wird diese mit sunset und sunrise befüllt:<br />
<br />
define SetDummy1 at *{sunset(-3600)} set Tageslicht hell <br />
define SetDummy2 at *{sunrise(+1800)} set Tageslicht dunkel <br />
<br />
Jetzt kann für jeden Wechsel ein eigener Offset gewählt werden, im Beispiel 3600 Sekunden vor Sonnenuntergang und 1800 Sekunden nach Sonnenaufgang. Anstatt das Dummy "Tageslicht" mit den Werten "hell/dunkel" zu befüllen, kann natürlich auch 1/0 oder "Tag/Nacht" etc. verwendet werden, je nach dem was bei der Anwendung besser passt.<br />
<br />
Für höhere Ansprüche könnte hingegen das [[Twilight]]-Modul verwendet werden, das Dämmerungsstufen kennt.<br />
<br />
===Struktur von "else if" Verzweigungen===<br />
define ... notify ... {\<br />
if ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
elsif ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
elsif ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
else {\<br />
if ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
}<br />
<br />
Achtung: es muss tatsächlich "elsif" heissen und nicht "elseif" oder "else if".<br />
<br />
Gilt für Perl Aufrufe. <br />
Wer aktuell in FHEM neu einsteigt kann auch den seit 2014 zur Verfügung stehenden Fhem Befehl [[DOIF]] verwenden, der bei ähnlichem Funktionsumfang wir Perl if/elsif übersichtlicher ist.<br />
<br />
== Dezember 2013==<br />
===notify durch mehrere Ereignisse auslösen lassen===<br />
Bekanntermassen löst<br />
<br />
:<code>define irgendwas notify MeinSchalter …</code><br />
<br />
aus, wenn irgendein Ereignis vom Sender "MeinSchalter" eintrifft.<br />
<br />
Mit<br />
<br />
:<code>define irgendwas notify MeinSchalter:on …</code><br />
<br />
wird das notify jedoch nur ausgelöst, wenn dieses Ereignis eine "on" ist.<br />
Wenn man aber möchte, das z.B. "on" und "off" auslöst (um etwa Dim-Befehle auszuschliessen) kann dies wie folgt erreicht werden:<br />
<br />
:<code>define irgendwas notify MeinSchalter:(on|off) …</code><br />
<br />
Die Klammern sind wichtig, vergleiche eine Lösung, bei der zwei Sender alternativ das notify auslösen können:<br />
<br />
:<code>define irgendwas notify MeinSchalter:on|MeinAndererSchalter:on …</code><br />
<br />
Selbstverständlich geht z.B. auch folgendes:<br />
<br />
:<code>define irgendwas notify MeinSchalter:on|MeinAndererSchalter …</code><br />
<br />
Hier wird ausgelöst wenn "MeinSchalter" das Ereignis "on" liefert oder "MeinAndererSchalter" irgendein Ereignis<br />
<br />
=== Aktoren über mehrere Funkschnittstellen ansprechen ===<br />
Falls man mehrere Funkschnittstellen zur Reichweitenverlängerung hat (CUL / CUNO etc), und ein Aktor von beiden Funkschnittstellen in etwa gleich (schlecht) erreichbar ist, mag der Wunsch aufkommen, einen Funkbefehl über beide Schnittstellen auszusenden. Dies ist bei Funkprotokollen möglich, die kein echtes Pairing der Aktoren an die Funkschnittstelle erfordern, also z.B. FS20 oder Intertechno, nicht jedoch ohne weiteres bei HomeMatic.<br />
<br />
Problematisch ist aber, dass die Funkschnittstelle über IODev eindeutige je Aktor festgelegt werden muss, eine Zuordnung mehrerer IODevs ist nicht vorgesehen.<br />
(wenn man IODev nicht setzt, wird per default die LETZTE definiert passende Schnittstelle verwendet)<br />
<br />
Dieses Problem kann mit einem Trick aber umgangen werden. Und zwar legt man den Aktor 2x mit gleicher Adresse aber abweichenden Namen und IOdevs an, z.B. so:<br />
<br />
<br />
define brenner_CUL1 FS20 11114244 11<br />
attr brenner_CUL1 IODev CUL1<br />
attr brenner_CUL2 room Keller<br />
<br />
define brenner_CUL2 FS20 11114244 11<br />
attr brenner_CUL2 IODev CUL2<br />
attr brenner_CUL2 room Keller<br />
<br />
Ein Befehl der Art:<br />
<br />
set brenner_CUL1,brenner_CUL2 on<br />
<br />
sendet den ON Befehl für den FS20 Aktor 11114244 11 jetzt tatsächlich über beide CULs aus!<br />
<br />
Achtung: Wenn die Schnittstellen gleichschnell angebunden sind, sollte vermutlich der [[Sendpool]] verwendet werden, da die Aussendungen sonst tatsächlich gleichzeitig erfolgen könnten und sich dann gegenseitig stören würden. Dieser Trick funktioniert ausserdem nur bei Befehlen, bei denen es im Zweifel egal ist, wenn sie beim Aktor 2x eintreffen. <br />
<br />
Bei HomeMatic lässt sich ein ähnlicher Effekt durch einrichten einer [[Virtueller Controller VCCU|virtuellen CCU]] erreichen.<br />
<br />
=== Retrycount bei FHTs ist überflüssig===<br />
Das von der Funktion ''autocreate'' älterer FHEM Versionen beim Anlegen von FHT80 Heizungsreglern voreingetragene attribute "retrycount" hat in den allermeisten Fällen keine Wirkung, da es NUR greift, wenn man als Funkschnittstelle eine FHZ1X00PC verwendet und dann den Softbuffer einschaltet. Selbst wenn man diese Konfiguration nutzt, will gut überlegt werden, ob die Wirkung postiv ist: Bei ungenügender Empfangslage vergrössert es Kommunikationsprobleme eventuell sogar.<br />
<br />
Es kann also in der Regel entfernt oder auf den Wert "1" gesetzt werden.<br />
<br />
define Heizung_Bad FHT 060d<br />
attr Heizung_Bad retrycount 3 <=== Diese Zeile entfernen<br />
<br />
Siehe auch:[[Kommunikationsprobleme mit FHT]]<br />
<br />
== November 2013 ==<br />
=== FS20 Funksteckdose sicherer schalten===<br />
Seltsamerweise kommt es vor, das FS20 Aktoren - insbesondere die FS20 Funksteckdose - an der Grenze der Funkreichweite bestimmte Befehle eines Typs empfängt, andere aber nicht. Z.B. lässt sich die FS20 Steckdose zwar immer einschalten, aber oft nicht mehr aus (oder umgekehrt).<br />
<br />
Gelegentlich kann man die Zuverlässigkeit erhöhen, indem man statt dem nicht funktionierenden Befehl das Gegenteil mit "for-timer 1" verwendet.<br />
<br />
Im Fall, dass eine FS20 Steckdose sich also einwandfrei EINschalten lässt:<br />
:<code>set SteckdoseA on</code><br />
aber oft ein AUSschalten mittels<br />
:<code>set SteckdoseA off</code><br />
nicht funktioniert, kann man versuchen die Dose anstelle mit "off" mit dem Befehl<br />
:<code>set SteckdoseA on-for-timer 1</code><br />
auszuschalten.<br />
<br />
Analog kann man mit off-for-timer arbeiten, wenn sich Aktoren nicht einschalten lassen, ausschalten aber geht.<br />
<br />
Achtung: Dieser Trick funtioniert ausdrücklich nur, wenn der "on/off-for-timer" Befehl im Aktor selber abgebildet wird. Daher ist der Trick vermutlich nicht auf andere Funksysteme übertragbar. z.B. unterstützt HM nur on-for-timer und Intertechno kennt keinen Timer.<br />
<br />
=== Mehrere Geräte zugleich schalten===<br />
Ein Ereignis soll mehrere Geräte schalten:<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1 on;;set Lampe2 on;;set FunksteckdoseA on</code><br />
<br />
Aus Übersichtlichkeitsgründen können vor und nach den Semikolons auch Leerzeichen eingefügt werden (obwohl in einigen Dokumentation behauptet wird, dies dürfe man nicht machen):<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1 on ;; set Lampe2 on ;; set FunksteckdoseA on</code><br />
<br />
Wenn der Schaltbefehl bei allen Geräten gleich ist, kann man wie folgt zusammenfassen:<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1,Lampe2,FunksteckdoseA on</code><br />
<br />
Das Komma wird nicht [[Escapen in Perlbefehlen|escaped]] (verdoppelt), hier darf tatsächlich KEIN Leerzeichen vor oder nach dem Komma eingefügt werden.<br />
<br />
=== Logfileinträge unterdrücken===<br />
Das Attribute "verbose 0" verhindert, dass das Gerät Logfileinträge erzeugt.<br />
<br />
Beispiel:<br />
<br />
define Funksteckdose FS20 22224222 01<br />
attr Funksteckdose verbose 0<br />
<br />
===FHT Lazy Mode benutzen===<br />
Es gibt wenig Gründe, den FHT "Lazy Mode" nicht zu verwenden<br />
define Heizung_Bad FHT 060d<br />
attr Heizung_Bad lazy<br />
<br />
Dieser sorgt dafür, dass Temperaturänderungen (genau genommen alle Änderungen, auch z.B. date) nur übertragen werden, wenn sie nicht sowieso schon am FHT eingestellt sind und veringern die Funklast dadurch deutlich. <br />
<br />
Siehe auch: [[Kommunikationsprobleme mit FHT]]<br />
<br />
== Oktober 2013 ==<br />
=== Zuverlässigkeit von Wiedereinschalten erhöhen ===<br />
Speziell bei FS20 Aktoren ist wegen des fehlenden Rückkanals nicht leicht erkennbar, ob ein Einschaltbefehl Wirkung gezeigt hat. Das hat ganz schlechten WAF, wenn man z.B. mit einem FS20 Aktor eine Heizung ausschaltet und das Wiedereinschalten nach z.B. einer Stunde nicht klappt.<br />
<br />
Hier empfiehlt es sich, das Ausschalten mittels <br />
:<code>set Heizungs_schalter off-for-timer 3584</code> (= fast eine Stunde)<br />
zu erledigen. Da bei FS20 der off-for-timer Befehl im Aktor abgewickelt wird (und nicht durch FHEM), schaltet sich der Aktor auch dann garantiert wieder ein, wenn Fhem abstürzt, eine Funkstörung vorliegt oder ähnliches. Bei Bedarf kann der Befehl off-for-timer zur Verlängerung der Ausschaltzeit wiederholt werden. Dies kann z.B. nötig sein, wenn die Ausschaltung länger als 4,5 Stunden (15360 Sekunden, der Maximalwert des Timers) dauern soll.<br />
<br />
Achtung: dieser Trick funktioniert nur, wenn der Aktor "off-for-timer" selbst beherrscht. FS20 Geräte können das, HomeMatic können aber nur "on-for-timer". Man kann off-for-timer mit HomeMatic trotzdem verwenden, aber in diesem Fall sendet Fhem den Einschaltbefehl nach der Timerzeit. InterTechno, RSL etc, können gar keinen Timer, hier sendet Fhem immer 2 Befehle im passenden Abstand.<br />
<br />
=== FS20 Timerzeiten ===<br />
FS20 Timer werden in Sekunden angegeben. Es sind jedoch nicht alle Werte einstellbar. Da der Timer Wert in 7 Bit übertragen werden muss, sind nur 128 Werte möglich. Um mit diesen Werten im unteren Bereich möglichst fein aufzulösen, andererseits aber auch lange Zeiten zu ermöglichen, ist die Verteilung nicht linear. Einstellbar sind folgende Zeiten in Sekunden;<br />
<br />
0,25 0,5 0,75 1 1,25 1,5 1,75 2 2,25 2,5 2,75 3 3,25 3,5 3,75 <br />
4 4,5 5 5,5 6 6,5 7 7,5 8 9 10 11 12 13 14 15 16 18 20 22 <br />
24 26 28 30 32 36 40 44 48 52 56 60 64 72 80 88 96 104 112 <br />
120 128 144 160 176 192 208 224 240 256 288 320 352 384 416 <br />
448 480 512 576 640 704 768 832 896 960 1024 1152 1280 1408 <br />
1536 1664 1792 1920 2048 2304 2560 2816 3072 3328 3584 3840 4096 <br />
4608 5120 5632 6144 6656 7168 7680 8192 9216 10240 11264 12288 <br />
13312 14336 15360 <br />
(etwas übersichtlicher formatiert auch [[FS20 Allgemein#ON/OFF Befehle mit Time Parameter|hier]]).<br />
<br />
Andere Zeiten werden von Fhem gerundet. Ein neues Setzen des Timer für FS20 löscht den alten Wert.</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Batterie%C3%BCberwachung&diff=16535Batterieüberwachung2016-10-06T09:24:14Z<p>Fabian: /* Geräte ohne Batteriestatus */ Einleitungssatz und Kleinkram im ersten Teilkapitel</p>
<hr />
<div>Verschiedene batteriebetriebene Geräte ([[:Kategorie:HomeMatic Components|Homematic]],RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Bei diesen kann der Batteriestatus übersichtlich dargestellt u/o aktiv überwacht werden. Bei Geräten ohne eigenen Batteriestatus muss man diesen "nachrüsten".<br />
<br />
<br />
== Geräte mit Batteriestatus ==<br />
<br />
=== Übersichtsdarstellung per readingsGroup ===<br />
Mit Hilfe einer ReadingsGroup kann einfach eine Übersicht aller Geräte mit "battery"-Reading erstellt werden, s. [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|hier]].<br />
<br />
<br />
=== Benachrichtigung per notify ===<br />
Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME : Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
'''Achtung:''' Für Nutzer eines [[HM-CC-RT-DN_Funk-Heizk%C3%B6rperthermostat|HM-CC-RT-DN]] muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:<br />
<br />
UG.Treppe.Heizung batteryLevel: 3.1 V<br />
<br />
Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME: Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel [[E-Mail_senden]] beschrieben.<br />
<br />
Testen kann man dies z.B. mit <code>trigger HeizungWZ Battery:low</code><br />
<br />
Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut <code>event-on-change-reading</code>).<br />
<br />
<br />
<br />
== Geräte ohne Batteriestatus ==<br />
Bei Geräten ohne Reading für den Batteriestatus kann man diesen auf verschiedene Weisen schätzen und als Reading eintragen. Dies funktioniert aber natürlich nur, wenn das Gerät sendet - bei einem rein empfangenden Aktor wie dem [[FHT 8v direkt ansprechen|FHT Stellantrieb]] klappt es also nicht... <br />
<br />
=== Erweiterung des Geräts um battery-Reading ===<br />
Mit Hilfe von [http://fhem.de/commandref_DE.html#userReadings userReadings] kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.<br />
<br />
Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.<br />
<br />
Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen): <br />
<br />
; Konfiguration:<br />
Lediglich der Schwellwert (600) braucht nach Wunsch angepasst zu werden, alles andere passt automatisch (vgl. [http://www.fhemwiki.de/wiki/Notify#Hinweise]).<br />
<br />
; Im Webinterface:<br />
<pre><br />
battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }<br />
</pre><br />
<br />
; Alternativ im Config-File:<br />
<pre><br />
attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>$NAME</code> - ist die Variable für das Device (und braucht nicht angepasst zu werden)<br />
: <code>battery {...}</code> - Name des userreadings mit Spezifikation, vgl. [http://fhem.de/commandref_DE.html#userReadings]<br />
: <code>return "ok" if ( ... );; return "low"</code> - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"<br />
: <code>time_str2num(ReadingsTimestamp($NAME,"state","0")</code> - Aktueller Timestamp in Sekunden, vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>time_str2num(OldTimestamp($NAME))</code> - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>600</code> - Schwellwert für "low" (600 sec = 10 min), nach Bedarf anpassen<br />
<br />
<br />
=== Alternativ per Skript ===<br />
<br />
Andere Komponenten, wie z. B. [[:Kategorie:FS20 Components|FS20 Komponenten]], übermitteln keinen Batteriestatus. <br />
<br />
Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in [[99_myUtils_anlegen|99_myUtils.pm]]:<br />
<br />
<pre>sub check_if_alive($$) {<br />
# Expects:<br />
# 1. Devicename to be checked<br />
# 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.<br />
# Returns:<br />
# 0 -> Device dead<br />
# 1 -> Device alive<br />
# 2 -> Error<br />
my ($Device,$hours_threshold) = @_;<br />
my ($Device) = @_;<br />
my $now = time;<br />
my $Timestamp = ReadingsTimestamp($Device,"state","0");<br />
if ($Timestamp eq "0") {<br />
return 2;<br />
}<br />
<br />
my @splitdatetime = split(/ /,$Timestamp);<br />
my @splitdate = split(/-/, $splitdatetime[0]);<br />
my @splittime = split(/:/, $splitdatetime[1]);<br />
my $last_state_time = timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);<br />
my $age_in_hours = ($now - $last_state_time) / 3600;<br />
<br />
if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
return 0;<br />
} else {<br />
return 1;<br />
}<br />
<br />
}</pre><br />
<br />
Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:<br />
<br />
<pre>*05:55:55 { <br />
check_if_alive("KS300", 12);<br />
}</pre><br />
<br />
KS300 ist dabei der Name des Devices in fhem. <br />
<br />
Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.<br />
<br />
Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.<br />
<br />
=== Visualisierung ===<br />
<br />
Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.<br />
<br />
Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:<br />
<br />
<pre>Internals: <br />
NAME dum_KS300_dead <br />
NR 795 <br />
STATE nein <br />
TYPE dummy <br />
Readings: <br />
2015-04-28 07:47:48 state nein <br />
Attributes: <br />
devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green</pre><br />
<br />
Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie. <br />
<br />
Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:<br />
<br />
<pre> if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
fhem("set dum_".$Device."_dead ja");<br />
return 0;<br />
} else {<br />
fhem("set dum_".$Device."_dead nein");<br />
return 1;<br />
}</pre><br />
<br />
Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.<br />
<br />
== Links ==<br />
<br />
* [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|visuelle Batterieüberwachung mit readingsGroup]]<br />
* [http://fhem.de/commandref_DE.html#userReadings commandref - userReadings]<br />
* [http://fhem.de/commandref_DE.html#perl commandref - Perl specials]<br />
* [[Notify#Hinweise|Hinweise zu Variablen]] (ansonsten auch an div. Stellen in der [http://fhem.de/commandref_DE.html commandref])<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Hardware]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Trick_der_Woche&diff=16534Trick der Woche2016-10-06T08:42:31Z<p>Fabian: Verweis zu Grundlagen der Heizungssteuerung gesetzt</p>
<hr />
<div>Diese Seite enthält Tipps und Tricks, die zu unbedeutend sind, einen eigenen Artikel zu rechtfertigen, alternative Schreibweisen/Lösungen für eine Problem darstellen, Ungenauigkeiten oder unklare Formulierungen in den offiziellen Dokumenten ergänzen und ähnliches. Jeder Eintrag ist typischerweise sehr kurz (wenige Zeilen lang) und beleuchtet vielleicht nur einen Aspekt von Fhem, er kann allgemeiner Natur sein, oder sich auf ein spezielles Gerät oder einen speziellen Anwendungsfall beziehen.<br />
<br />
<br />
<br />
== Oktober 2016 ==<br />
<br />
=== Grundlagen der Heizungssteuerung ===<br />
Der Artikel [[Grundlagen der Heizungssteuerung]] soll einen zentralen Einstiegspunkt und eine Übersicht der Möglichkeiten insb. für Neulinge in FHEM bieten.<br />
<br />
<br />
== Mai 2016 ==<br />
=== DbLog reparieren ===<br />
Sollte ein fhem mit DbLog Probleme machen, oder auf der SQL-Konsole Fehler werfen, so ist eine Reparatur der DB fällig. Das ist auf der Kommandozeile verhältnismäßig einfach möglich und wird im Kapitel [[DbLog#Datenbank reparieren]] beschrieben.<br />
<br />
=== DbLog bearbeiten ===<br />
Unerwünschte Einträge in den Loggings treten immer wieder mal auf. Wie man dies in einer Datenbank korrigiert, dazu gibt das Kapitel [[DbLog#Bearbeitung von Datenbank-Einträgen]] eine erste Einführung.<br />
<br />
=== Pollenflug ===<br />
In dieser schönen Jahreszeit werden manche durch Heuschnupfen geplagt. Auf der Seite [[Pollenflug]] wird beschrieben, wie man eine Pollenvorhersage in fhem einbinden kann - hilft zwar nicht gegen das Niesen, ist aber trotzdem ganz informativ... ;-)<br />
<br />
== April 2016 ==<br />
=== HomeMatic und VCCU ===<br />
HomeMatic Nutzer sollten unbedingt eine [[Virtueller Controller VCCU|VCCU]] einrichten und nutzen.<br />
Die Einrichtung ist unaufwändig und schafft jede Menge Vorteile, auch beim Einsetzen nur einer Schnittstelle wie z.B. einem [[HM-CFG-LAN LAN Konfigurations-Adapter]]. Auch die nachträglich Einrichtung ist problemlos, sofern vorher nur ein I/O Gerät ("Funkschnittstelle") verwendet wurde.<br />
<br />
== Dezember 2015 ==<br />
===defmod===<br />
In vielen Fällen will man mit einer Aktion gleichzeitig eine andere Aktion bereits für später festlegen, z.b. nach Einschalten einer Heizung durch einen Bewegungsmelder diese eine Stunde später wieder ausschalten.<br />
<br />
Dies kann z.B. durch ein Konstrukt dieser Art erledigt werden:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; define reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
<br />
Nachteilig ist, dass bei einer weiteren Auslösung des Bewegungsmelders die Heizzeit nicht verlängert wird, da eine Neudefinition von '''reset_Heizung''' mit der Fehlermeldung '''reset_Heizung already exists, delete it first''' quittiert wird. Die Lösung bisher war, das alte '''reset_Heizung''' zunächst zu löschen und dann erneut mit neuem Zeitstempel anzulegen:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; delete reset_Heizung ;; define reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
Aber auch dieses umständliche Konstrukt hat noch einen Nachteil: Es erzeugt bei einer ersten Auslösung eine Fehlermeldung, weil '''reset_Heizung''' noch nicht exisitert und daher nicht gelöscht werden kann. Dies liesse sich abfangen, was die Konstruktion weiter verkomplizieren würde.<br />
<br />
Daher hat Rudolf König mit FHEM 5.6 den neuen Befehel "defmod" eingeführt, der ein noch nicht existieredendes define neu anlegt (wie "define"), eine bereits vorhandenes aber direkt ändert (wie "delete" und danach "define")<br />
<br />
Dadurch lässt sich verkürzt schreiben:<br />
:<code>define Heizung_an notify Bewegung set HZG_WZ desired-temp 22 ;; defmod reset_Heizung at +01:00:00 set HZG_WZ desired-temp 16</code><br />
<br />
<br />
<br />
== April 2015 ==<br />
===FS20 Timer===<br />
FS20 Aktoren beherrschen zwei verschiedene Timer-Methoden.<br />
<br />
Angenommen ein FS20 Device heisse "Lampe" und sei z.B. ein [[FS20_SU_Unterputz-Funk-Schalter|FS20 SU]] (Unterputzschalter), dann kann man mit FHEM sowohl <br />
:<code> set Lampe on-for-timer 30</code><br />
verwenden um die Lampe 30 Sekunden einzuschalten, aber auch zunächst in den FS20 SU die maximale Einschaltdauer einprogrammieren:<br />
:<code> set Lampe timer 30</code><br />
Dannach wird jedes normale<br />
:<code> set Lampe on</code><br />
die Lampe für nur 30 Sekunden einschalten.<br />
<br />
Als Timerwerte kommen in beiden Fällen die bekannten [[Trick_der_Woche#FS20_Timerzeiten|128 Sekundenwerte]] von 0,25 Sekunden bis Etwa 4,5 Stunden in Frage.<br />
<br />
Es ist offenbar nicht bei allen Aktoren möglich einen einmal eingestellten Timer zu löschen, neue Werte eingeben aber sehr wohl.<br />
<br />
Mehr hier: [[FS20_Allgemein#Gerätetimer setzen / löschen|FS20 timer]].<br />
<br />
== Februar 2015 ==<br />
=== 1-wire am GPIO4-Port des RaspberryPi funktioniert nicht mehr nach Systemupdate ===<br />
Es kann passieren, dass nach einem Systemupdate (apt-get update oder apt-get dist-upgrade) die 1-wire-Geräte am GPIO4-Port plötzlich nicht mehr funktionieren. Eine Problemlösung dazu ist im Artikel "[[Raspberry Pi und 1-Wire#1-wire am GPIO4-Port funktioniert nicht mehr nach Systemupdate]]" beschrieben.<br />
<br />
=== Backup der Konfiguration (fhem.cfg und fhem.state) bei jedem "save" ===<br />
Der nachfolgende Codeschnipsel erstellt bei jedem "save" eine Kopie der aktuellen [[Konfiguration]] (fhem.cfg und fhem.state) in ein Verzeichnis "backup_cfg-state" welches unter /opt/fhem/ zu finden ist. Somit kann bei einem Fehler jederzeit auf den letzten Stand zurückgegangen werden.<br />
Zuerst ins FHEM Befehlsfeld den folgenden Befehl eingeben:<br />
:<code>{ `mkdir backup_cfg-state` } </code><br />
<br />
Danach folgendes [[notify]] anlegen:<br />
define backupCfg notify global:SAVE {\<br />
my $now = TimeNow();; $now =~ s/ /_/g;; \<br />
`cp $attr{global}{configfile} ./backup_cfg-state/fhem.cfg.$now`;;\<br />
`cp $attr{global}{statefile} ./backup_cfg-state/fhem.state.$now`;;\<br />
} <br />
<br />
Quelle: {{Link2Forum|Topic=30873|Message=234412|LinkText=FHEM-Forum}}<br />
<br />
== Januar 2015 ==<br />
=== CUL & CO über Serial ID-einbinden ===<br />
Bei mehreren USB-Geräten kann es vorkommen, dass sie vertauscht werden z.B. ''/dev/ttyUSB0'' zu'' /dev/ttyUSB1'' oder ''/dev/ttyACM0'' zu ''/dev/ttyACM1''.<br />
<br />
Um dies zu umgehen, kann man sie über ihre Serial-ID in Fhem einbinden.<br />
<br />
Dieser Befehl zeigt die Serial-ID:<br />
<br />
:<code>ls -l /dev/serial/by-id</code><br />
<br />
Hier die Beispielausgabe eines CUL868, JeeLink, RFXtrx und eines CUL433<br />
<br />
user@xxxx:~# ls -l /dev/serial/by-id<br />
lrwxrwxrwx 1 root root 13 Jan 9 23:34 usb-busware.de_CUL868-if00 -> ../../ttyACM0<br />
lrwxrwxrwx 1 root root 13 Jan 9 13:26 usb-FTDI_FT232R_USB_UART_A901RQ9F-if00-port0-> ../../ttyUSB0<br />
lrwxrwxrwx 1 root root 13 Jan 9 13:26 usb-RFXCOM_RFXtrx433_A1WZWL5Y-if00-port0-> ../../ttyUSB1<br />
lrwxrwxrwx 1 root root 13 Jan 9 21:29 usb-busware.de_CUL433-if00 -> ../../ttyACM1 <br />
<br />
Damit lässt sich folgende Definition erstellen:<br />
<br />
z.B. für einen CUL868<br />
<br />
:<code>define CUL868 CUL /dev/serial/by-id/usb-busware.de_CUL868-if00@9600 1134</code><br />
<br />
oder einen JeeLink<br />
<br />
:<code>define Jeelink JeeLink /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A901RQ9F-if00-port0@57600</code><br />
<br />
'''Einschränkung:''' Bei CULs von Busware lassen sich nur CUL433 und CUL868 unterscheiden. Zwei CUL868 haben z.B. immer die gleiche Serial-ID.<br />
<br />
=== HM LAN Konfig-Adapter Antenne verbessern===<br />
Die Antenne des [[HM-CFG-LAN LAN Konfigurations-Adapter]] kann man mit etwas Bastelgeschick verlängern um den Empfang zu verbessern. <br />
<br />
Sinnvoll ist die Verlängerung auf 1/2 Lambda (868MHz = 17,27 cm) oder gar 1 Lambda.<br />
1 Lambda Antennen haben starke Richtwirkung in Form eines gedachten Zylinders, dessen Mittelachse die Antenne ist.<br />
D.h., Alles was sich in Richtung des Anfangs und des Endes des Antennedrahtes befindet, hat schlechteren Empfang als mit einer kurzen Antenne. Daher muss man die Antenne ggf. genauer ausrichten.<br />
<br />
Anleitungen dazu werden an verschiedenen Stellen veröffentlicht, z.B. in <br />
[http://www.ip-symcon.de/forum/threads/18411-Umbau-HM-LAN-Adapter-auf-Lambda-1-2-Dipol-Antenne diesem Beitrag] im IP-Symcon Forum (anders als der Namen der Anleitung vermuten lässt, liegt hier kein Dipol vor, sondern eine "normale" 1 Lambda Antenne.)<br />
<br />
Prinzipiell so dünnen Draht wie möglich verwenden.<br />
<br />
Wer noch mehr rausholen will, kann auch zusätzlichen Aufwand betreiben und die Antenne etwas von der Elektronik entfernen, die nämlich Störstrahlung in die Antenne einkoppelt. Oder eine Groundplane bauen.<br />
Ein Anleitung für die CCU (analog auch für den HM LAN Konfig-Adapter einsetzbar) gibt es [http://www.techwriter.de/beispiel/funkeige.htm hier].<br />
<br />
== Dezember 2014 ==<br />
=== FHT80TF als "Prüfsender" einsetzen ===<br />
Da der [[FHT80TF-2]] günstig ist und seinen Zustand ca. alle zwei Minuten sendet, kann er gut zum Ermitteln der Funklage von [[SlowRF]] Komponenten genutzt werden, auch wenn diese nicht senden. Den RSSI einer FS20 Schaltsteckdose kann man z.B. nicht wissen, da die Dose nur ein Empfänger ist. Wenn eine Dose nicht gut funktioniert und man den Verdacht hat, dass sie funktechnisch ungünstig liegt, kann man einen [[FHT80TF-2]] neben die Steckdose legen und man bekommt nach zwei Minuten einen Wert, der (trotz umgekehrter Funkrichtung) gut genug ist, um einem Hinweise zu geben.<br />
<br />
<br />
== November 2014 ==<br />
=== FS20 Adressschema und die Rolle des Hauscodes ===<br />
[[FS20_Allgemein#FS20_Adressierungsschema_.28Vorschlag.29]]<br />
<br />
<br />
== Oktober 2014 ==<br />
=== Aktor für Wanddosen ohne Nulleiter ===<br />
Zwar gibt es viele Aktoren, die man in Wanddosen hinter Schaltern einbauen kann, oft scheitert deren Nutzung aber daran, dass in vielen Elektroinstalltionen in der Wanddose eines (Licht)schalters kein Nulleiter verlegt ist, den die meisten Aktoren zur eigenen Stromversorgung brauchen. Hier kann der [[RSL 2-Draht Einbauschalter]] helfen, der auch ohne Nulleiter funktioniert und kompatibel zu InterTechno ist. Er lässt sich z.B. mit einem CUL(433) schalten. Problematisch ist allerdings das Schalten von LED Lampen.<br />
<br />
<br />
<br />
== August 2014 ==<br />
=== Perl-Skripte Online testen ===<br />
Im Internet existieren Webseiten auf denen man Perl-Code online testen kann. Beispielsweise auf [http://www.tutorialspoint.com/execute_perl_online.php codingground] kann man Code zum Testen eingeben und die Auswirkungen betrachten. Dies eignet sich zur schnellen Fehleranalyse oder um Perl zu lernen. Natürlich lassen sich keine Fhem-Besonderheiten nutzen.<br />
<br />
== Juli 2014 ==<br />
=== Funklast reduzieren===<br />
Bewegungsmelder erzeugen in der Regel eine recht hohe Funklast, wenn sie oft ausgelöst werden, also z.B. Licht in einem Zimmer schalten sollen.<br />
<br />
Konstruktionen der Art:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* set Licht_Flur on-for-timer 256</code><br />
haben daher den Nachteil bei viel Bewegung im Flur und je nach Einstellung des Sendeabstandes des Bewegungsmelders mindestens alle 120 Sekunde oder öfter ein <br />
:<code>on-for-timer 256</code><br />
zu senden. Das erzeugt eine hohe Funklast, speziell wenn der Aktor ein SlowRF Gerät ist (z.B. FS20 Unterputzschalter).<br />
In solchen Fällen kann es helfen, nur dann einen Befehl zu senden, wenn das Licht nicht schon an ist:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* { if (Value("Licht_Flur") eq "off") { fhem ("set Licht_Flur1 on-for-timer 256") } }</code><br />
Nachteilig ist aber, dass eine Auslösung innerhalb 256 Sekunden die Einschaltzeit nicht verlängert. Dies kann man umgehen, indem man nicht on-for-timer verwendet, sondern den Aktor selber verzögert auschaltet und bei weiteren Auslösungen nur die Verzögerung erneut anlegt:<br />
:<code>define FlurLicht notify Bewegungsmelder_Flur:motion:.* { if (Value("Licht_Flur1") eq "off") { fhem ("set Licht_Flur on ;; define FlurLicht_aus at +00:04:16 set Licht_Flur off") } else { fhem ("delete FlurLicht_aus ;; define FlurLicht_aus at +00:04:16 set Licht_Flur off") }}</code><br />
Durch den relativ neuen Befehl "defmod" kann ausserdem das Löschen und neu Anlegen zusammengefasst werden, sieh Tipp Dezember 2015<br />
<br />
== Juni 2014 ==<br />
=== Batteriestatus bei HomeMatic Devices aktivieren===<br />
Zumindest einige (wenn nicht alle) batteriegespeisten HM-Geräte können Batteriemeldungen senden, tun dies in der normalen Konfiguration aber nicht.<br />
Dazu muss das Register cyclicInfoMsg auf on gesetzt werden. <br />
<br />
Wie man das macht steht z.B. hier<br />
[[HM-SEC-SC_Tür-Fensterkontakt#Batteriestatus_aktivieren]]<br />
und hier<br />
[[HomeMatic_Type_ThreeState]]<br />
<br />
== Mai 2014 ==<br />
=== Dummywert mit aktueller Uhrzeit versehen in anderen Dummy kopieren===<br />
Der Inhalt von Dummy1 soll erweitert um Uhrzeit und Datum in Dummy2 kopiert werden (z.B. um die Urzeit der letzten Auslösung einer Alarmanlage anzuzeigen)<br />
:<code>{ fhem("set dummy2 " . (Value("Dummy1")." ".TimeNow()) ) } </code><br />
<br />
=== Zwei Dummywerte in einen anderen Dummy kopieren ===<br />
Der String in Dummy1 soll um den String in Dummy2 erweitert und nach Dummy3 kopiert werden:<br />
:<code>{ fhem("set Dummy3 ".(Value("Dummy1")+Value("Dummy2"))) } </code><br />
(Achtung: "+" ist Zahlen addieren, "." ist String konkatenieren) <br />
<br />
== April 2014==<br />
=== Code sparen ===<br />
Wer Definitionen wie die aus dem März zum [[Trick der Woche#Zuverlässigkeit von FS20 Schaltungen erhöhen|Abfangen von Fehlbedienungen]] verwendet, kann durch eine ELSE Erweiterung auch gleich das Auschalten erledigen.<br />
:<code>define act_on_TV_on notify TV { if ("$EVENT" eq "on" || "$EVENT" eq "dimup") { fhem("set TV on") } else { fhem("set TV off") } }</code><br />
<br />
Hierdurch schaltet ON oder versehentlich zu langes Drücken (also DIMUP) den Fernseher ein, jeder ''andere'' Tastendruck (also insbesondere die OFF Taste oder zu langes Drücken der OFF Taste -> DIMDOWN) den Fernseher aus.<br />
<br />
Voraussetzung ist, dass die Fernbedienung standardkonfiguriert ist, siehe auch nächster Tip.<br />
<br />
=== Konfiguration eines FS20 Senders prüfen ===<br />
Gelegentlich reagieren bestimmte notifys nicht, die von Sendern (Fernbedienungen, Sensoren oder Schaltern) ausgelöst werden sollen. Speziell bei FS20 aber auch bei HomeMatic kann das daran liegen, dass der Sender nicht sendet was man denkt. So gut wie alle FS20 Sender kennen nämlich nicht nur ON und OFF, sondern über ein Dutzend Schaltzustände. Dimmen ist einem noch hinreichend bewusst, es gibt aber auch exotische Dinge wie Ein-für-Zeitdauer, Ein-auf-alte-Helligkeit, Aus-für-Zeitdauer (nur FS20), Ein-für-Zeitdauer-dannach-alter-Zustand und vieles mehr.<br />
<br />
Was also ein Infrarot-Bewegungsmelder bei Auslösung sendet und auch was eine Fernbedienungstaste sendet ist einstellbar. Wenn jetzt zum Beispiel an einer Fernbedienung auf Tastendruck nicht ON sondern Ein-für-Zeitdauer (ON-FOR-TIMER) gesendet wird, wird<br />
:<code>define act_on_TV_on notify TV:on set TV on</code><br />
seltsamerweise nicht auslösen, obwohl die richtige Taste (und diese auch nicht zu lang) gedrückt wurde.<br />
<br />
Auch wenn man sich sicher ist, das Richtige in die Fernbedienung/Sensoren einprogramiert zu haben, ist ein einfacher Test immer, dies mit<br />
:<code>define act_on_TV notify TV set TV on</code><br />
zu prüfen. Dieses notify löst immer aus, wenn "TV" ''irgendetwas'' sendet, egal was. (Beachte: Man kann dann den Fernseher aber nicht mehr ausschalten, da auch die Austaste das notify auslöst und zum TV-Aktor nur "on" sendet). Geht die Schaltung jetzt (kann man den Fernseher also jetzt EINschalten), liegt der Verdacht nahe, dass die Konfiguration des Senders / Sensors anders ist, als man denkt. Das Logfile gibt Aufschluss, welcher Befehl tatsächlich empfangen wurde.<br />
<br />
=== Alles in FHEM, nichts in der Fernbedienung ===<br />
Versuche in deiner FHEM Umgebung nicht, das Verhalten von Aktoren durch entsprechende Befehle aus Sensoren oder Fernbedienungen zu steuern. An Besten senden die nur ON und OFF oder DIM, den Rest möglichst immer in FHEM erledigen. <br />
<br />
Wer eine Lampe immer für vier Minuten einschalten will, programmiert seinen Schalter (Fernbedienung) also so, das nur "on" gesendet wird und erledigt den Rest in FHEM:<br />
:<code>define act_on_Schalter notify Schalter set Lampe-on-for-timer 240</code><br />
<br />
Vielfach wird argumentiert, das eine dirkete Kopplung die Zuverlässigkeit erhöht, da bei einem Ausfall von FHEM der Aktor totzdem schaltbar sei.<br />
Überlege, ob es hier nicht weniger komplex ist, die Zuverlässigkeit der FHEM Instanz zu erhöhen.<br />
<br />
== März 2014==<br />
=== Zuverlässigkeit von FS20 Schaltungen erhöhen ===<br />
FS20 Fernbedienungen senden bei Tastendrücken von mehr als 0,4 Sekunden anstatt ON bzw. OFF DIMUP bzw DIMDOWN.<br />
<br />
Das führt gelegentlich zu allgemein schlechter Bedienbarkeit (und schlechtem WAF), da 0,4 Sekunden relativ kurz ist und gerne aus versehen länger gedrückt wird. Das ist vor allem problematisch, wenn etwas geschaltet werden soll, was keinen Dimmer hat oder Dimmen nicht unterstützt.<br />
<br />
Eine Konfiguration wie <br />
:<code>define act_on_TV_on notify TV:on set TV on</code><br />
hat also dann den Nachteil, dass bei versehentlich zu langem Tastendruck das TV nicht angeht. Da die meisten Nutzer unbewusst dazu neigen, bei Misserfolg die selbe Taste erneut aber länger zu drücken (was erneut keinen Erfolg zeigt) ist Frustration zu erwarten.<br />
<br />
Es kann daher speziell bei nicht dimmbaren Aktoren von Vorteil sein, auch dimmen abzufangen, z.B. durch eine zweite zusätzliche Definition:<br />
<br />
:<code>define act_on_TV_dimup notify TV:dimup set TV on</code><br />
<br />
Es ist in der Regel einfacher, einige dieser zusätzlichen Definitionen einzufügen, als allen Bedienern des Systems zu erklären, dass man keinesfalls länger als 0,4 Sekunden drücken darf.<br />
<br />
Alternativ kann man auch beide Befehle in einer Definition durch Perlbefehle {} abfangen:<br />
<br />
:<code>define act_on_TV_on notify TV { if ("$EVENT" eq "on" || "$EVENT" eq "dimup") { fhem("set TV on") }}</code><br />
<br />
Andere Möglichkeiten vergleiche: [[Trick der Woche#notify durch mehrere Ereignisse auslösen lassen|Notify durch mehrere Ereignisse auslösen lassen]]<br />
<br />
== Februar 2014==<br />
=== Sequence nutzen ===<br />
Man kann Aktionen statt mit einem Tastedruck auch mit einer Sequenz von Tastendücken auslösen. Das Format des Befehle ist:<br />
<br />
:<code>define <name> sequence <re1> <timeout1> <re2> [<timeout2> <re3> ...] </code><br />
<br />
wobei <re1> ...<re_n> die Aktionen sind und <timeout_n> der maximale Abstand der Tastendrücke in Sekunden.<br />
<br />
Angenommen, man wolle z.B. eine Lampe dann anschalten, wenn man zuerst Taste1 EIN, dann Taste2 AUS und dann wieder Taste1 EIN einer Fernbedienung drückt, könnte das konkret so aussehen:<br />
<br />
:<code>define MeineLampenSequenz1 sequence Btn1:on 0.5 Btn2:off 0.5 Btn1:on</code><br />
<br />
Zwischen jedem der Tastendrücke darf eine halbe Sekunde Abstand sein. Diese Definition selbst löst die Lampe nicht aus, sondern definiert nur wie die Sequenz aussehen soll. Um die Lampe bei erfolgreicher Betätigung der Sequenz auch einzuschalten, bedarf es zusätzlich etwas wie:<br />
<br />
:<code>define MeineLampe notify MeineLampenSequenz1:trigger set Lampe on</code><br />
<br />
Sequence kann man gut nutzen, um mit einer Fernbedienung mehr Funktionen zu schalten als Tasten zur Verfügung stehen. Ebenso könnte man damit simple Codeschlösser für Alarmanlagen bauen, z.B. um eine Anlage auszuschalten, wenn eine bestimmte Abfolge von Tasten gedrückt wird.<br />
<br />
Je nach Funksystem nimmt die Zuverlässigkeit aber rasch ab. Angenommen im Bereich FS20 (das System ist etwas unzuverlässiger ist als z.B. HomeMatic) seien 95% aller Funktsignale ungestört übertragbar, dann würden in der Praxis von 100 Tastendrücken an einer Fernbedienung 95x Erfolg zeigen und 5x fehlschlagen; das ist sicher tolerabel. <br />
<br />
Bei einer Sequenzlänge von nur 4 Tasten würde die kombinierte Erfolgsquote der Sequenz jedoch nur noch ca. 80% sein, zum Ausschalten einer Alarmanlage vermutlich bereits unpraktisch.<br />
<br />
== Januar 2014==<br />
===isday===<br />
Bekanntlich kann man mit "isday" leicht testen ob es draussen hell ist oder nicht. isday ist eine Funktion des (automatisch geladenen) Moduls [[SUNRISE_EL]], das auch sunset und sunrise enthält.<br />
<br />
Problematisch bei isday ist die fehlende Möglichkeit, Sonnenaufgang und Untergang einzustellen (zumindest wenn man nicht 99_SUNRISE_EL.pm verändern will): isday ist wahr, wenn die Sonne im gegebenen Breitengrad sichtbar ist. Wenn örtliche Gegebenheiten eine Anpassung erfordern, kann man sich auch ein eigenes isday basteln, in dem man sunrise und sunset verwendet und dieses mit getrennten offsets versieht.<br />
<br />
Zuerst definiert man sich eine Variable ("dummy") der anstelle isday eingesetzt werden soll, z.B.:<br />
<br />
:<code>define Tageslicht dummy </code><br />
<br />
Dann wird diese mit sunset und sunrise befüllt:<br />
<br />
define SetDummy1 at *{sunset(-3600)} set Tageslicht hell <br />
define SetDummy2 at *{sunrise(+1800)} set Tageslicht dunkel <br />
<br />
Jetzt kann für jeden Wechsel ein eigener Offset gewählt werden, im Beispiel 3600 Sekunden vor Sonnenuntergang und 1800 Sekunden nach Sonnenaufgang. Anstatt das Dummy "Tageslicht" mit den Werten "hell/dunkel" zu befüllen, kann natürlich auch 1/0 oder "Tag/Nacht" etc. verwendet werden, je nach dem was bei der Anwendung besser passt.<br />
<br />
Für höhere Ansprüche könnte hingegen das [[Twilight]]-Modul verwendet werden, das Dämmerungsstufen kennt.<br />
<br />
===Struktur von "else if" Verzweigungen===<br />
define ... notify ... {\<br />
if ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
elsif ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
elsif ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
else {\<br />
if ... {\<br />
fhem ("... ;; ...")\<br />
}\<br />
}<br />
<br />
Achtung: es muss tatsächlich "elsif" heissen und nicht "elseif" oder "else if".<br />
<br />
Gilt für Perl Aufrufe. <br />
Wer aktuell in FHEM neu einsteigt kann auch den seit 2014 zur Verfügung stehenden Fhem Befehl [[DOIF]] verwenden, der bei ähnlichem Funktionsumfang wir Perl if/elsif übersichtlicher ist.<br />
<br />
== Dezember 2013==<br />
===notify durch mehrere Ereignisse auslösen lassen===<br />
Bekanntermassen löst<br />
<br />
:<code>define irgendwas notify MeinSchalter …</code><br />
<br />
aus, wenn irgendein Ereignis vom Sender "MeinSchalter" eintrifft.<br />
<br />
Mit<br />
<br />
:<code>define irgendwas notify MeinSchalter:on …</code><br />
<br />
wird das notify jedoch nur ausgelöst, wenn dieses Ereignis eine "on" ist.<br />
Wenn man aber möchte, das z.B. "on" und "off" auslöst (um etwa Dim-Befehle auszuschliessen) kann dies wie folgt erreicht werden:<br />
<br />
:<code>define irgendwas notify MeinSchalter:(on|off) …</code><br />
<br />
Die Klammern sind wichtig, vergleiche eine Lösung, bei der zwei Sender alternativ das notify auslösen können:<br />
<br />
:<code>define irgendwas notify MeinSchalter:on|MeinAndererSchalter:on …</code><br />
<br />
Selbstverständlich geht z.B. auch folgendes:<br />
<br />
:<code>define irgendwas notify MeinSchalter:on|MeinAndererSchalter …</code><br />
<br />
Hier wird ausgelöst wenn "MeinSchalter" das Ereignis "on" liefert oder "MeinAndererSchalter" irgendein Ereignis<br />
<br />
=== Aktoren über mehrere Funkschnittstellen ansprechen ===<br />
Falls man mehrere Funkschnittstellen zur Reichweitenverlängerung hat (CUL / CUNO etc), und ein Aktor von beiden Funkschnittstellen in etwa gleich (schlecht) erreichbar ist, mag der Wunsch aufkommen, einen Funkbefehl über beide Schnittstellen auszusenden. Dies ist bei Funkprotokollen möglich, die kein echtes Pairing der Aktoren an die Funkschnittstelle erfordern, also z.B. FS20 oder Intertechno, nicht jedoch ohne weiteres bei HomeMatic.<br />
<br />
Problematisch ist aber, dass die Funkschnittstelle über IODev eindeutige je Aktor festgelegt werden muss, eine Zuordnung mehrerer IODevs ist nicht vorgesehen.<br />
(wenn man IODev nicht setzt, wird per default die LETZTE definiert passende Schnittstelle verwendet)<br />
<br />
Dieses Problem kann mit einem Trick aber umgangen werden. Und zwar legt man den Aktor 2x mit gleicher Adresse aber abweichenden Namen und IOdevs an, z.B. so:<br />
<br />
<br />
define brenner_CUL1 FS20 11114244 11<br />
attr brenner_CUL1 IODev CUL1<br />
attr brenner_CUL2 room Keller<br />
<br />
define brenner_CUL2 FS20 11114244 11<br />
attr brenner_CUL2 IODev CUL2<br />
attr brenner_CUL2 room Keller<br />
<br />
Ein Befehl der Art:<br />
<br />
set brenner_CUL1,brenner_CUL2 on<br />
<br />
sendet den ON Befehl für den FS20 Aktor 11114244 11 jetzt tatsächlich über beide CULs aus!<br />
<br />
Achtung: Wenn die Schnittstellen gleichschnell angebunden sind, sollte vermutlich der [[Sendpool]] verwendet werden, da die Aussendungen sonst tatsächlich gleichzeitig erfolgen könnten und sich dann gegenseitig stören würden. Dieser Trick funktioniert ausserdem nur bei Befehlen, bei denen es im Zweifel egal ist, wenn sie beim Aktor 2x eintreffen. <br />
<br />
Bei HomeMatic lässt sich ein ähnlicher Effekt durch einrichten einer [[Virtueller Controller VCCU|virtuellen CCU]] erreichen.<br />
<br />
=== Retrycount bei FHTs ist überflüssig===<br />
Das von der Funktion ''autocreate'' älterer FHEM Versionen beim Anlegen von FHT80 Heizungsreglern voreingetragene attribute "retrycount" hat in den allermeisten Fällen keine Wirkung, da es NUR greift, wenn man als Funkschnittstelle eine FHZ1X00PC verwendet und dann den Softbuffer einschaltet. Selbst wenn man diese Konfiguration nutzt, will gut überlegt werden, ob die Wirkung postiv ist: Bei ungenügender Empfangslage vergrössert es Kommunikationsprobleme eventuell sogar.<br />
<br />
Es kann also in der Regel entfernt oder auf den Wert "1" gesetzt werden.<br />
<br />
define Heizung_Bad FHT 060d<br />
attr Heizung_Bad retrycount 3 <=== Diese Zeile entfernen<br />
<br />
Siehe auch:[[Kommunikationsprobleme mit FHT]]<br />
<br />
== November 2013 ==<br />
=== FS20 Funksteckdose sicherer schalten===<br />
Seltsamerweise kommt es vor, das FS20 Aktoren - insbesondere die FS20 Funksteckdose - an der Grenze der Funkreichweite bestimmte Befehle eines Typs empfängt, andere aber nicht. Z.B. lässt sich die FS20 Steckdose zwar immer einschalten, aber oft nicht mehr aus (oder umgekehrt).<br />
<br />
Gelegentlich kann man die Zuverlässigkeit erhöhen, indem man statt dem nicht funktionierenden Befehl das Gegenteil mit "for-timer 1" verwendet.<br />
<br />
Im Fall, dass eine FS20 Steckdose sich also einwandfrei EINschalten lässt:<br />
:<code>set SteckdoseA on</code><br />
aber oft ein AUSschalten mittels<br />
:<code>set SteckdoseA off</code><br />
nicht funktioniert, kann man versuchen die Dose anstelle mit "off" mit dem Befehl<br />
:<code>set SteckdoseA on-for-timer 1</code><br />
auszuschalten.<br />
<br />
Analog kann man mit off-for-timer arbeiten, wenn sich Aktoren nicht einschalten lassen, ausschalten aber geht.<br />
<br />
Achtung: Dieser Trick funtioniert ausdrücklich nur, wenn der "on/off-for-timer" Befehl im Aktor selber abgebildet wird. Daher ist der Trick vermutlich nicht auf andere Funksysteme übertragbar. z.B. unterstützt HM nur on-for-timer und Intertechno kennt keinen Timer.<br />
<br />
=== Mehrere Geräte zugleich schalten===<br />
Ein Ereignis soll mehrere Geräte schalten:<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1 on;;set Lampe2 on;;set FunksteckdoseA on</code><br />
<br />
Aus Übersichtlichkeitsgründen können vor und nach den Semikolons auch Leerzeichen eingefügt werden (obwohl in einigen Dokumentation behauptet wird, dies dürfe man nicht machen):<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1 on ;; set Lampe2 on ;; set FunksteckdoseA on</code><br />
<br />
Wenn der Schaltbefehl bei allen Geräten gleich ist, kann man wie folgt zusammenfassen:<br />
<br />
:<code>define act_on_Bewegungsmelder notify Bewegungsmelder set Lampe1,Lampe2,FunksteckdoseA on</code><br />
<br />
Das Komma wird nicht [[Escapen in Perlbefehlen|escaped]] (verdoppelt), hier darf tatsächlich KEIN Leerzeichen vor oder nach dem Komma eingefügt werden.<br />
<br />
=== Logfileinträge unterdrücken===<br />
Das Attribute "verbose 0" verhindert, dass das Gerät Logfileinträge erzeugt.<br />
<br />
Beispiel:<br />
<br />
define Funksteckdose FS20 22224222 01<br />
attr Funksteckdose verbose 0<br />
<br />
===FHT Lazy Mode benutzen===<br />
Es gibt wenig Gründe, den FHT "Lazy Mode" nicht zu verwenden<br />
define Heizung_Bad FHT 060d<br />
attr Heizung_Bad lazy<br />
<br />
Dieser sorgt dafür, dass Temperaturänderungen (genau genommen alle Änderungen, auch z.B. date) nur übertragen werden, wenn sie nicht sowieso schon am FHT eingestellt sind und veringern die Funklast dadurch deutlich. <br />
<br />
Siehe auch: [[Kommunikationsprobleme mit FHT]]<br />
<br />
== Oktober 2013 ==<br />
=== Zuverlässigkeit von Wiedereinschalten erhöhen ===<br />
Speziell bei FS20 Aktoren ist wegen des fehlenden Rückkanals nicht leicht erkennbar, ob ein Einschaltbefehl Wirkung gezeigt hat. Das hat ganz schlechten WAF, wenn man z.B. mit einem FS20 Aktor eine Heizung ausschaltet und das Wiedereinschalten nach z.B. einer Stunde nicht klappt.<br />
<br />
Hier empfiehlt es sich, das Ausschalten mittels <br />
:<code>set Heizungs_schalter off-for-timer 3584</code> (= fast eine Stunde)<br />
zu erledigen. Da bei FS20 der off-for-timer Befehl im Aktor abgewickelt wird (und nicht durch FHEM), schaltet sich der Aktor auch dann garantiert wieder ein, wenn Fhem abstürzt, eine Funkstörung vorliegt oder ähnliches. Bei Bedarf kann der Befehl off-for-timer zur Verlängerung der Ausschaltzeit wiederholt werden. Dies kann z.B. nötig sein, wenn die Ausschaltung länger als 4,5 Stunden (15360 Sekunden, der Maximalwert des Timers) dauern soll.<br />
<br />
Achtung: dieser Trick funktioniert nur, wenn der Aktor "off-for-timer" selbst beherrscht. FS20 Geräte können das, HomeMatic können aber nur "on-for-timer". Man kann off-for-timer mit HomeMatic trotzdem verwenden, aber in diesem Fall sendet Fhem den Einschaltbefehl nach der Timerzeit. InterTechno, RSL etc, können gar keinen Timer, hier sendet Fhem immer 2 Befehle im passenden Abstand.<br />
<br />
=== FS20 Timerzeiten ===<br />
FS20 Timer werden in Sekunden angegeben. Es sind jedoch nicht alle Werte einstellbar. Da der Timer Wert in 7 Bit übertragen werden muss, sind nur 128 Werte möglich. Um mit diesen Werten im unteren Bereich möglichst fein aufzulösen, andererseits aber auch lange Zeiten zu ermöglichen, ist die Verteilung nicht linear. Einstellbar sind folgende Zeiten in Sekunden;<br />
<br />
0,25 0,5 0,75 1 1,25 1,5 1,75 2 2,25 2,5 2,75 3 3,25 3,5 3,75 <br />
4 4,5 5 5,5 6 6,5 7 7,5 8 9 10 11 12 13 14 15 16 18 20 22 <br />
24 26 28 30 32 36 40 44 48 52 56 60 64 72 80 88 96 104 112 <br />
120 128 144 160 176 192 208 224 240 256 288 320 352 384 416 <br />
448 480 512 576 640 704 768 832 896 960 1024 1152 1280 1408 <br />
1536 1664 1792 1920 2048 2304 2560 2816 3072 3328 3584 3840 4096 <br />
4608 5120 5632 6144 6656 7168 7680 8192 9216 10240 11264 12288 <br />
13312 14336 15360 <br />
(etwas übersichtlicher formatiert auch [[FS20 Allgemein#ON/OFF Befehle mit Time Parameter|hier]]).<br />
<br />
Andere Zeiten werden von Fhem gerundet. Ein neues Setzen des Timer für FS20 löscht den alten Wert.</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Anwendungsszenarien&diff=16533Anwendungsszenarien2016-10-06T08:38:05Z<p>Fabian: Verweis zu Grundlagen der Heizungssteuerung gesetzt</p>
<hr />
<div>Diese Seite stellt eine "redaktionell bearbeitete" Liste von Anwendungsszenarien dar. Weitere, ähnliche Aufstellungen finden sich in den Kategorielisten <br />
* [[:Kategorie:Examples|Examples]] für komplette Beispiele<br />
* [[:Kategorie:Code Snippets|Code Snippets]] für kleine Schnipsel mit einzelnen Befehlen und/oder Definitionen<br />
* und auf der Seite "[[Wie kann ich...]]"<br />
<br />
Finden sich hier Links auf Forenbeiträge oder externe Seiten, so sind diese als "gewünschte Seite" zu interpretieren.<br />
<br />
== Szenarien ==<br />
{| class="wikitable" <br />
|-<br />
| style="width:50%" | <!-- Spalte 1 (links) --><br />
* (Haus-)Informations- und Steuerzentrale<br />
** Mittels [[RSS]] generiertes Übersichtsbild (ausführlicher Workshop verfügbar)<br />
** Digitaler Bilderrahmen mit [[Digitaler Bilderrahmen | eingeblendeten FHEM-Daten]] oder zur [[Digitaler_Bilderrahmen_mit_lcd4linux| Anzeige von FHEM-Grafiken]]<br />
** [[Statusdisplay Fritzbox 7390]]<br />
** [[Kindle_Display]] (Fhem Informationen als Screensaver)<br />
<br />
* Telefon <br />
** [[Telefonat als Auslöser für Aktionen]]<br />
** ...<br />
<br />
* Rollladensteuerung<br />
** [[Jalousie und Beleuchtung in mehreren Räumen]]<br />
** [[Slider für HM-Rolladensteuerung anzeigen]]<br />
** [[Rolladensteuerung mit FS20SM8]]<br />
** ...<br />
<br />
* Heizungssteuerung<br />
** [[Grundlagen der Heizungssteuerung]]<br />
** [[Heizungskontrolle Einfach]] (Englische Version: [[Heating Control Basic]])<br />
** [[Junkers Therme Stetigregelung]]<br />
** Heizungssteuerung mit [[HCS]] und/oder [[Heating Control]]<br />
** 3/4-Wege-Mischer-Steuerung mit [[STELLMOTOR]]: [[Mischersteuerung]]<br />
** Vorlauf-Energiebedarf mit [[VALVES]]: [[Raumbedarfsabhängige Heizungssteuerung]]<br />
** Heizungsoptimierung (Mischer, Pumpe) [[Heizung:_Verbrauchsoptimierung,_Radiator/Fußboden-Steuerung]]<br />
<br />
* Balkon und Garten<br />
** [[Bewässerungssteuerung]] <br />
** ...<br />
<br />
* Lüftung und Klima<br />
** [[Energiesparende Schimmelbekämpfung / Luftentfeuchtung in kritischen Räumen]]<br />
** ...<br />
<br />
* Auto, Verkehr<br />
** [[Spritpreismonitor]] sammelt und visualisiert die Preisentwicklung an ausgewählten Tankstellen<br />
<br />
| style="width:50%" | <!-- Spalte 2 (rechts) --><br />
<br />
* Finanzen<br />
** [[STOCKQUOTES|Wertpapierkurse verfolgen/protokollieren]]<br />
** ...<br />
<br />
* Helligkeitsgeführte Steuerung<br />
** [[Twilight Anwendungsbeispiel]]<br />
** ...<br />
<br />
* Terminerinnerungen, Kalenderintegration<br />
** Erinnerung an Müllabfuhr, etc.: {{Link2Forum|Topic=26209|LinkText=Forenthema}} und ein {{Link2Forum|Topic=32382|LinkText=weiteres Forenthema}}<br />
** ...<br />
<br />
* Zugriff auf FHEM "von außen"<br />
** [[FritzBox Webzugriff absichern]]<br />
** [[FB7390 VPN-Zugang einrichten]]<br />
** ...<br />
<br />
* Anwesenheitssimulation / -steuerung<br />
** [[Anwesenheitserkennung]]<br />
** ...<br />
<br />
* Zugangskontrolle, Fenster, Tür und Tor<br />
** [[DoorPi_und_FHEM | Türsprechstelle mit DoorPi]]<br />
** [[Garagentorsteuerung]]<br />
** {{Link2Forum|Topic=11715|LinkText=Zugangskontrolle mit Keymatic, Fingerabdruck, RFID}} (Forum; sollte noch ins Wiki integriert werden)<br />
** ...<br />
<br />
* (Video-)Überwachung<br />
** Einbindung von (Web-)Cam Bildern / Streams<br />
** ...<br />
<br />
* Energieverbrauch / -erzeugung<br />
** [[Ertragsmessung Solarthermie]]<br />
** [[Heizleistung und Gasverbrauch]]<br />
<br />
* Rundfunk / Fernsehen / Multimedia<br />
** {{Link2Forum|Topic=28123|LinkText=Aktuelles TV-Programm}} auflisten (Forenthema)<br />
** ...<br />
<br />
* Sonstiges<br />
** [[Watchdog kombiniert mit Threshold|Auf ausbleibende Aktionen oder Ereignisse reagieren]]<br />
** mit Fhem realisierte [[Zeitschaltuhr]]<br />
** [[Temperaturfarbe | Temperatur in Farbe]] und [[Farbtemperatur | Farbe in Temperatur]]<br />
|}<br />
<br />
Sofern hier statt Verweisen auf andere Wiki-Seiten Forenthemen verlinkt sind, sind alle Wiki-Schreiber herzlich eingeladen, die Informationen aus dem Forum in einer (neuen) Wiki-Seite zu konsolidieren.<br />
<br />
[[Kategorie:Examples]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Grundlagen_der_Heizungssteuerung&diff=16532Grundlagen der Heizungssteuerung2016-10-06T08:35:32Z<p>Fabian: Initial erstellt - um Ergänzung wird gebeten.... ;-)</p>
<hr />
<div>{{Hinweis|Dieser Artikel ist im Aufbau und soll die verschiedensten Möglichkeiten einer Heizungssteuerung aufzeigen und einen Einstiegspunkt zu den Varianten geben. Alle sind eingeladen hier weitere Möglichkeiten einzubringen.}}<br />
<br />
Es gibt viele verschiedene Möglichkeiten die Temperatur in Räumen zu steuern. Welche Varianten überhaupt möglich sind, hängt stark von den vorhandenen technischen Komponenten ab, auf die man Einfluss nehmen kann - wer seinen eigenen Heizkessel steuern kann, hat andere Möglichkeiten als wenn man in einer Mietswohnung in einem Mehrparteienhaus wohnt.<br />
<br />
Dieser Artikel soll die verschiedenen Möglichkeiten zur Steuerung von Heizungen und Heizungsanlagen aufzeigen und auf weiterführende Artikel verweisen. Grundsätzlich werden solche Artikel in den Kategorien [[:Kategorie:Heizungssteuerung|Heizungssteuerung]] und [[:Kategorie:Heizungsventile|Heizungsventile]] aufgelistet.<br />
<br />
<br />
== Steuerung ohne Zugriff auf die zentrale Heizungsanlage ==<br />
Wohnt man bspw. zur Miete in einem Mehrparteienhaus, hat man üblicherweise keinen Zugriff auf die zentralen Heizungskomponenten wie Brenner und Pumpen. In diesem Fall bleibt einem nur die Heizungssteuerung über die Heizkörper, Fussboden- oder Wandheizung.<br />
<br />
<br />
=== Heizungsventile und Systeme ===<br />
Hierbei können verschiedene mehr oder weniger intelligente und ausbaubare Heizungsventile und Systeme eingesetzt werden. Dabei ist zu beachten, dass es vernetzbare und nicht vernetzbare Systeme gibt:<br />
* vernetzbare Ventile und Systeme:<br />
** [[HomeMatic]]<br />
** [[:Kategorie:FHT Components|FHT]]<br />
** [[MAX]]<br />
** [[HM-CC-RT-DN Funk-Heizkörperthermostat|HM-CC-RT-DN bzw. eQ3]]<br />
** [[FS20 Allgemein|FS20]]<br />
** [[Heizungssteuerung 1-Wire|Eigenbau mit 1-wire]]<br />
** ...<br />
* nicht vernetzbare Ventile:<br />
** [[:Kategorie:FHT Components|FHT]]<br />
** ...<br />
<br />
<br />
=== Einsatzszenarien ===<br />
* Steuerung nach Wochenplan (am Gerät setzen, in fhem setzen)<br />
* Steuerung durch fhem (vollständig oder override)<br />
* Steuerung durch Anwesenheit (presence oder geofencing)<br />
* Einbindung von Temperatursensoren etc<br />
* ...<br />
<br />
<br />
<br />
=== Weitere Möglichkeiten und Beispiele ===<br />
* [[Heizung mit Bewegungsmelder steuern]]<br />
* [[Alarmanlage|Kopplung mit Alarmanlage]]<br />
* [[Heizungskontrolle Einfach]]<br />
* [[Zuhause-Status]]<br />
* [[Heating Control]]<br />
* ...<br />
<br />
<br />
== Steuerung mit Zugriff auf die zentrale Heizungsanlage ==<br />
Hat man Zugriff auf die zentralen Heizungskomponenten (Brenner, Pumpen, Sonnenkollektoren, Lüftungsanalgen, Wärmepumpen, ...) hat man nicht nur die oben beschriebenen, sondern auch die Möglichkeit diese zentralen Komponenten zu steuern.<br />
<br />
<br />
=== Einsatzszenarien ===<br />
* Steuerung von Heizkessel, Sonnenkollektor, Wärmepumpe, ...<br />
* Steuerung von Pumpen<br />
* Einbindung der Raumthermostate<br />
* Einbindung von Innen-/Aussen-Sensoren (Temp/Hum/...)<br />
* Einbindung von Lüftungsanlagen<br />
* ...<br />
<br />
<br />
=== Weitere Möglichkeiten und Beispiele ===<br />
* [[Heizung: Verbrauchsoptimierung, Radiator/Fußboden-Steuerung]]<br />
* [[Ölverbrauchsanzeige / Betriebsstundenzähler]]<br />
* [[ZHK]]<br />
* [[STELLMOTOR]]<br />
* [[Raumbedarfsabhängige Heizungssteuerung]]<br />
* ...<br />
<br />
<br />
<br />
== Energiemessung ==<br />
Eine Übersicht verschiedener Artikel zur Energiemessung liefern die folgenden Kategorien: <br />
* [[:Kategorie:Energieverbrauchsmessung]]<br />
* [[:Kategorie:Energieerzeugungsmessung]]<br />
<br />
<br />
[[Kategorie:Heizungssteuerung]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Heating_Control&diff=16531Heating Control2016-10-06T08:22:32Z<p>Fabian: Kategorien gesetzt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Heizungssteuerung über ein Wochen-Heizprofil<br />
|ModType=h<br />
|ModCmdRef=Heating_Control<br />
|ModForumArea=Unterstuetzende Dienste<br />
|ModTechName=98_Heating_Control.pm<br />
|ModOwner=dietmar63 / {{Link2FU|405|Dietmar63}}<br />
}}<br />
<br />
[[Heating Control]] ist ein Fhem-Erweiterungsmodul zur Heizungssteuerung über ein Wochen-Heizprofil.<br />
<br />
== Voraussetzungen ==<br />
Keine.<br />
<br />
== Anwendung ==<br />
=== Define ===<br />
Das Heizprofil wird angelegt mit<br />
:<code>define <name> Heating_Control <device> [<language>] <profile> <command>|<condition> </code><br />
<br />
=== Attribute ===<br />
<br />
=== Ausführung ===<br />
Die Kommandos zur Steuerung werden mit dem Befehl<br />
:<pre>set <device> (desired-temp|desiredTemerature) <temp></pre><br />
zum definierten Zeitpunkt an das Gerät gesendet.<br />
<br />
== Anwendungsbeispiele ==<br />
* Vorstellung einer Lösung im {{Link2Forum|Topic=23783|LinkText=Fhem Forum}}, die [[Heating Control]] und [[HCS]] miteinander kombiniert.<br />
<br />
<br />
Grundsätzlich nutzte ich FHZ1300, FHT8b mit Fensterkontakten an FHEM.<br />
Die Steuerung der Heizung erfolgt komplett über FHEM, die FHTs laufen alle auf manuell.<br />
<br />
Erweiterung: Mittlerweile migriere ich von FHT auf HM und somit ergeben sich ein paar Änderungen am Code, welche ich hier angefügt habe. Auch nutze ich immer mehr das Modul DOIF, weswegen sich zusätzlich einige Codes geändert haben (allerdings um einiges einfacher).<br />
<br />
Den Code zum definieren der FHTs/HMs spare ich mir jetzt, das sollte Grundverständnis sein.<br />
<br />
Als erstes Modul meiner Steuerung nutze ich das Modul Heating_Control für jedes Zimmer/jeden FHT/jedes HM:<br />
<br />
<pre>define HCB Heating_Control FHT_Bad 12345|06:00|22 12345|07:30|19 67|08:30|22 67|10:00|19 18:00|21 22:00|14 (ReadingsVal("HCAutomatik", "state", "") eq "on")<br />
attr HCB alias Bad<br />
attr HCB group Heizplan<br />
attr HCB room Heizung</pre><br />
<br />
Wobei gilt: <Wochentage 1-7>|<Uhrzeit hh:mm>|<Temperatur in °C><br />
<br />
Den Heizplan kann ich über einen Dummy ein- und ausschalten:<br />
<br />
<pre>define HCAutomatik dummy<br />
attr HCAutomatik alias Heizungsautomatik<br />
attr HCAutomatik devStateIcon on:general_an off:general_aus<br />
attr HCAutomatik group Automatik<br />
attr HCAutomatik icon sani_heating_automatic<br />
attr HCAutomatik room Heizung<br />
attr HCAutomatik sortby 1<br />
attr HCAutomatik webCmd on:off</pre><br />
<br />
Die neuen HM Theromstate habe ich in eine Structur gepakt<br />
<br />
<pre><br />
define Heizungsventile structure Heizungen HZ_Bad_Clima HZ_Dachboden_Clima HZ_Flur_unten_Clima HZ_Klo_Clima HZ_Flur_oben_Clima<br />
</pre><br />
<br />
Hier die Abfrage des Dummys<br />
<br />
<pre><br />
define HeatingControl.Aktivator DOIF ([HCAutomatik] eq "on") (set HCS_System on) DOELSE (set FHT_.* desired-temp 14.0,set Heizungsventile desired-temp 14.0,set HCS_System off,set Pushover msg 'FHEM' 'Heizplan ausgeschalten')</pre><br />
<br />
Bei einer Deaktivierung werden alle FHTs/HMs auf 14 Grad eingestellt und es wird mir zu Info eine Pushnachricht geschickt.<br />
<br />
Als nächstes habe ich das Modul HCS integriert:<br />
<br />
<pre>define HCS_System HCS Vaillant<br />
attr HCS_System alias Vaillant Steuerung<br />
attr HCS_System devStateIcon demand:sani_heating_temp idle:sani_heating_manual off:general_aus<br />
attr HCS_System deviceCmdOff off<br />
attr HCS_System deviceCmdOn on<br />
attr HCS_System event-on-change-reading state,devicestate,eco,overdrive<br />
attr HCS_System icon sani_heating_manual<br />
attr HCS_System idleperiod 5<br />
attr HCS_System interval 5<br />
attr HCS_System loglevel 5<br />
attr HCS_System mode thermostat<br />
attr HCS_System room Heizung<br />
attr HCS_System thermostatThresholdOff 0.5<br />
attr HCS_System thermostatThresholdOn 0.5<br />
attr HCS_System valveThresholdOff 40<br />
attr HCS_System valveThresholdOn 35<br />
<br />
define Vaillant CUL_HM 123456<br />
attr Vaillant IODev HMLan<br />
attr Vaillant alias Vaillant Therme<br />
attr Vaillant autoReadReg 4_reqStatus<br />
attr Vaillant devStateIcon on:general_an off:general_aus<br />
attr Vaillant expert 2_full<br />
attr Vaillant firmware 1.6<br />
attr Vaillant group HCS<br />
attr Vaillant icon sani_boiler_temp<br />
attr Vaillant model HM-LC-SW1-BA-PCB<br />
attr Vaillant msgRepeat 1<br />
attr Vaillant peerIDs 00000000,<br />
attr Vaillant room Heizung<br />
attr Vaillant subType switch<br />
attr Vaillant webCmd on:off</pre><br />
<br />
Hiermit steuere ich meine Vaillant Heizung potentialfrei über einen HM Empfänger an.<br />
Das Relais ist so angeschlossen, dass die Heizung an ist, wenn das Relais abgefallen ist (dies hat den Vorteil, dass auch bei einem Defekt des Empfängers die Heizung funktioniert).<br />
<br />
<br />
Des weiteren habe ich mir einen "ECO-Script" angelegt (vielen Dank an das Forum für die Hilfe), welcher alle FHTs um 2 Grad runter setzt und zwar von dem im Moment anliegenden Wert:<br />
<br />
<pre>define HZ.Absenkung dummy<br />
attr HZ.Absenkung alias ECO Mode - Heizungsabsenkung 2 Grad<br />
attr HZ.Absenkung devStateIcon on:general_an off:general_aus<br />
attr HZ.Absenkung group Automatik<br />
attr HZ.Absenkung icon time_eco_mode<br />
attr HZ.Absenkung room Heizung<br />
attr HZ.Absenkung webCmd on:off</pre><br />
<br />
Dann habe ich dazu folgendes in meiner 99_myUtils.pm angelegt:<br />
<br />
<pre><br />
sub ecomode {<br />
my @FHT=devspec2array("TYPE=FHT");<br />
foreach(@FHT)<br />
{<br />
my $tp = ReadingsVal("$_", "desired-temp", "")-2;<br />
if (ReadingsVal("$_", "desired-temp", "") > "16") {<br />
fhem("set $_ desired-temp ".$tp)<br />
}<br />
}<br />
} <br />
<br />
sub ecomodeHM {<br />
my @HM_HT=devspec2array("HZ_.*._Clima");<br />
foreach(@HM_HT)<br />
{<br />
my $tpHM = ReadingsVal("$_", "desired-temp", "")-2;<br />
if (ReadingsVal("$_", "desired-temp", "") > "16") {<br />
fhem("set $_ desired-temp ".$tpHM)<br />
}<br />
}<br />
}</pre><br />
<br />
<br />
Diese ECO-Schalter triggere ich auch über das Modul [[PRESENCE]] und Geofancy an. Der "watchdog" wird bei Abwesenheit aktiviert und läuft 30 Minuten. Wenn bis dahin niemand zurück hin, wird ECO aktiviert:<br />
<br />
<pre><br />
define ECO.Mode.Aktivator DOIF([Anwesenheit] eq "Unterwegs") ({ecomode},{ecomodeHM}) DOELSEIF ([HZ.Absenkung] eq "on" or [Sonnenindikator] eq "on") ({ecomode},{ecomodeHM}) DOELSE ({Heating_Control_SetAllTemps()}<br />
attr ECO.Mode.Aktivator wait 3600</pre><br />
<br />
Zusätzlich trigger ich ECO über die Aussentemperatur. Wird 22 Grad erreicht oder überschritten, wird ECO aktiviert. Unterhalb 22 Grad wieder deaktiviert:<br />
<br />
<pre>define Sonnenindikator dummy<br />
attr Sonnenindikator devStateIcon on:sun27 off:sun7<br />
attr Sonnenindikator group HCS<br />
attr Sonnenindikator icon clear3<br />
<br />
define Aussentemp.Check DOIF ([Wetterstation:temperature] >= "22") (set Sonnenindikator on) DOELSE (set Sonnenindikator off)</pre><br />
<br />
Für meine neuen HM Thermostate musste ich dann noch etwas bzgl. Fenster ändern, da Fhem beim setzten der Temeratur das Thermostat übersteuert.<br />
Somit kann es z.B. vorkommen, dass ein Fenster noch offen ist, wenn fhem eine neue Temperatur schickt und die Heizung hoch heizt, obwohl das Fenster noch offen ist.<br />
<br />
Um das zu umgehen, habe ich eine einfach Abfrage eingebaut:<br />
<br />
<pre><br />
define Fenster.Status.Bad DOIF ([Fenster_Bad] eq "open") (set HCB disbale) DOELSE (set HCB enable)<br />
</pre><br />
<br />
Dies soll als "Denkanstoss" dienen. Ich habe mir auch alles zu FHEM aus diesem Forum "gezogen".<br />
Nachbau erlaubt und erwünscht.<br />
<br />
{{Todo|Screenshots ergänzen}}<br />
<br />
<!-- Detaillierte Beispiele bitte als eigenen Abschnitt (=== Überschrift ===) einfügen --><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=10011|LinkText=Thread zum Modul}} im Fhem Forum<br />
* {{Link2Forum|Topic=23783|LinkText=Thread zum Anwendungsbeispiel}} im Fhem Forum<br />
* Modulbeschreibung zu [[HCS]]<br />
* [http://www.fischer-net.de/hausautomation/fhem/54-fhem-modul-hcs-ueberarbeitet.html HCS Modul] auf fischer-net.de<br />
<br />
<br />
[[Kategorie:Heizungssteuerung]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=%C3%96lverbrauchsanzeige_/_Betriebsstundenz%C3%A4hler&diff=16530Ölverbrauchsanzeige / Betriebsstundenzähler2016-10-06T08:19:48Z<p>Fabian: Kategorien gesetzt</p>
<hr />
<div>{{Randnotiz|RNTyp=y|RNText=Die gezeigten (''notify'') Codebeispiele sind für die (nicht empfohlene) direkte Eingabe in die Konfigurationsdatei. Bei Eingabe über das Webinterface müssen entsprechende Anpassungen vorgenommen werden.}}<br />
Problem: oft weiß man nicht, wie viel Öl man tatsächlich verbraucht und welche Veränderungen an der Heizung welche Auswirkungen haben.<br />
<br />
Die Lösung: eine Ölverbrauchsanzeige direkt in FHEM.<br />
<br />
Hierfür habe ich ein Relais (Finder 55.34.8.230.0040 [http://www.elv.de/elv-fs20-kse-funk-klingelsignal-erkennung.html ELV]) so angeschlossen, dass wenn der Brenner einschaltet sich der Kontakt am anderen Ende öffnet, dadurch kein Strom mehr zum KSE fließt und der dann "on" an FHEM sendet. Logischerweise hätte ich gedacht, es muss so angeschlossen sein, dass Strom zum KSE fließt wenn der Brenner an ist, dies hat aber nicht funktioniert, daher andersrum. Das Relais ist ein Wechsler, daher kein Problem.<br />
FHEM erstellt durch [[autocreate]] automatisch ein neues Device, definiert sieht es bei mir so aus:<br />
<br />
<nowiki>define fs_boiler FS20 1be4 00<br />
attr fs_boiler devStateIcon on:HeizungOn off:HeizungOff<br />
attr fs_boiler dummy 1<br />
attr fs_boiler eventMap on:off off:on<br />
attr fs_boiler icon icoHEIZUNG<br />
attr fs_boiler model fs20kse</nowiki><br />
Und der entsprechende Plot:<br />
<br />
<nowiki>define FileLog_fs_boiler FileLog ./log/fs_boiler-%Y.log fs_boiler<br />
attr FileLog_fs_boiler logtype fs20:Window,text<br />
define weblink_fs_boiler weblink fileplot FileLog_fs_boiler:fs20:CURRENT</nowiki><br />
Die Icons für die Heizung habe ich irgendwo aus dem Forum, weiß allerdings nicht mehr welcher Thread.<br />
<br />
So, nun wird zumindest schonmal dargestellt, wann die Heizung an oder aus ist.<br />
Um den Ölverbauch zu messen werden einige weitere Definitionen benötigt.<br />
<br />
Zuerst ein [[notify]]:<br />
<nowiki>define boiler_consumption notify fs_boiler {\<br />
if("$EVENT" eq "on") {\<br />
$data{boiler_last} = time();;\<br />
} elsif("$EVENT" eq "off") {\<br />
$data{boiler_min} = (time()-$data{boiler_last})/60*0.03626;;\<br />
fhem &quot;trigger boiler_consumption $data{boiler_min}&quot;;;\<br />
}\<br />
}</nowiki><br />
<br />
Dieser berechnet aus der Differenz zwischen on und off Minutengenau den Verbrauch. Hierfür muss man wissen, welche Düse verbaut ist und was für einen Durchsatz sie hat. Unsere hat 2,5kg/Stunde Durchsatz (steht auf der Düse) dies habe ich in Liter umgerechnet (laut Wikipedia besitzt Heizöl eine Dichte von 0,820–0,860 kg/l [http://de.wikipedia.org/wiki/Heizöl [1]]) und dies anschließend durch 60 geteilt um es als Liter/Minute darzustellen. Daher kommt der Wert 0.03626 im ''notify''.<br />
Hierzu nun der Log und Plot:<br />
<br />
<nowiki>define boiler_log FileLog ./log/boiler-%Y-%m.log boiler_consumption<br />
define Oilconsumption weblink fileplot boiler_log:oil:CURRENT<br />
attr Oilconsumption label sprintf(&quot;Consumption (l) today:&#160;%.2f total&#160;%.2f avg/h&quot;, $data{sum1}, ($data{sum1}/$hour))</nowiki><br />
Der Gplot-Syntax folgt gleich. Zuerst eine kurze Erklärung. Ich lasse im Label den Tagesverbrauch auf 2 Nachkommastellen gerundet sowie den aktuellen Durschnittsverbrauch Anzeigen. Leider funktioniert der Durschnittsverbrauch nur für den aktuellen Tag und nicht für vorherige, da immer durch die Aktuelle Stunde geteilt wird, bei vorherigen Tagen müsste aber durch 24 geteilt werden. Habe ich noch nicht geschafft.<br />
Die gplot für den Plot:<br />
<br />
<nowiki>############################<br />
# Display the oil consumption.<br />
# 2012-12-24_14:48:31 boiler_consumption 0.2634893333<br />
set terminal png transparent size &lt;SIZE&gt; crop<br />
set output '&lt;OUT&gt;.png'<br />
set xdata time<br />
set timefmt &quot;%Y-%m-%d_%H:%M:%S&quot;<br />
set xlabel &quot; &quot;<br />
set ytics<br />
set y2tics<br />
set title '&lt;L1&gt;'<br />
set grid xtics y2tics<br />
set y2label &quot;Oilconsumption (l)&quot;<br />
set ylabel &quot;Oilconsumption (l)&quot;<br />
#FileLog 3::0:<br />
plot &quot;&lt;IN&gt;&quot; using 1:3 title 'Oilconsumption (l)' with lines</nowiki><br />
Das wärs für die Verbrauchsanzeige. Das meiste hiervon basiert auf verschiedene Beiträge aus dem Forum und google-groups.<br />
<br />
Zur Kontrolle oder Alternativ kann man auch einen Betriebsstundenzähler programmieren:<br />
<br />
<nowiki>define boiler_time notify fs_boiler {\<br />
if("$EVENT" eq &quot;on&quot;) {\<br />
$data{boiler_last} = time();;\<br />
} elsif("$EVENT" eq &quot;off&quot;) {\<br />
$data{boiler_min} = (time()-$data{boiler_last})/60;;\<br />
fhem &quot;trigger boiler_time $data{boiler_min}&quot;;;\<br />
}\<br />
}<br />
define boiler_time_log FileLog ./log/boiler_time-%Y-%m.log boiler_time</nowiki><br />
Hier lasse ich nur ein Log schreiben, ich benötige keinen Plot, müsste aber mit leichter Anpassung der oben stehenden gplot-Definition leicht zu bewerkstelligen.<br />
<br />
Zusätzlich binde ich noch eine Grafik mit dem Ölpreisverlauf direkt von Tecson ein:<br />
<br />
<nowiki>define Heizoel weblink image http://www.tecson.de/tl_files/pepesale/bilder_inhalt/_hoel.gif<br />
attr Heizoel htmlattr width=&quot;551&quot; height=&quot;594&quot;</nowiki><br />
<br />
== Links ==<br />
* Forenthread, in dem eine {{Link2Forum|Topic=15641|LinkText=Änderung/Erweiterung}} diskutiert wird<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Energieverbrauchsmessung]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Heizung:_Verbrauchsoptimierung,_Radiator/Fu%C3%9Fboden-Steuerung&diff=16529Heizung: Verbrauchsoptimierung, Radiator/Fußboden-Steuerung2016-10-06T08:05:03Z<p>Fabian: Kategorien gesetzt</p>
<hr />
<div>Diese Seite beschreibt die Optimierungen und fhem-Installation bezüglich der Heizungssteuerung in unserem Haus von 1904, welches wir im Sommer 2014 gekauft haben und beschreibt die notwendigen Schritte und Ergebnisse zur Kostenreduzierung.<br />
<br />
__TOC__<br />
<br />
== Ausgangssituation ==<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-Heizung.jpg|mini|rechts|'''Bild 1''': Viessmann Mono-Vitola b-f mit Weishaupt Gasbrenner]]<br />
<br />
Mit Übergabe des Hauses war als Ausgangssituation vorhanden:<br />
<br />
* 16 Räume im Erdgeschoß und ausgebauten Dachboden, davon<br />
# 7 Räume nur mit Radiatoren<br />
# 5 Räume nur mit Fußbodenheizung<br />
# 2 Räume unbeheizt<br />
# 2 Räume kombiniert beheizt mit Radiatoren und Fußbodenheizung<br />
* Viessmann Mono-Vitola b-f mit 43kW Weishaupt-Gasbrenner und Holzkammer (seit 10 Jahren nicht mehr benutzt), siehe Bild 1<br />
* Viessmann Tetramatik Heizungssteuerung mit digitaler Schaltuhr SU und außentemperaturabhängiger Steuerung WS<br />
* Warmwassererzeugung über 200l Boiler, rein elektrisch<br />
* 1100m Fußbodenverrohrung im Estrich/Beton in Kupferohr<br />
* Grundfoss Umwälzpumpe mit 170W Verbrauchsleistung für die Fußbodenheizung<br />
* 17 Radiatoren mit vier verschiedenen Thermostatköpfen und Heizungsventilen<br />
* Gasverbrauch von 73.000kWh im Jahr und 380 EUR Abschlagzahlung im Monat<br />
* Ein Viessmann 4-fach Mischer, der den max. 40 Grad Vorlauf für die Fußbodenheizung erzeugte<br />
* Eine UPONOR Funksteuerung für die Fußbodenheizung im Obergeschoß mit unbeschrifteten Funkthermostaten<br />
<br />
== Probleme nach dem Einzug ==<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-Fussbodenmischer.jpg|mini|rechts|'''Bild 2''': Fussbodenmischer und -pumpen]]<br />
Bereits im Winter 2014/2015 gab es erhebliche Probleme mit der Heizung. Einzelne Räume wurden maximal 18 Grad warm, andere überhitzten schnell. Unterschritt die Außentemperatur die Frostgrenze, fing die Fußbodenheizung an zu "stottern": der Mischer stand morgens in einer Stellung, die das aufgeheizte Kesselwasser direkt und schnell in die Fußbodenheizung einspeiste. Als Folge deaktivierte ein Thermostat (auf 60 Grad eingestellt) die Fußbodenpumpe und das Wasser mußte langsam abkühlen (60-90 Minuten), bis die Pumpe wieder ansprang und wieder sofort abgeschaltet wurde - denn die Tetramatik hat die Mischerstellung nicht verändert.<br />
<br />
Kurzfristig wurde das Problem durch eine neue Einstellung der Heizkurven entschärft. Die Radiatoren benötigten jedoch einen bis zu 75°C warmen Vorlauf, um die Zimmer im Obergeschoß auf 18 Grad aufzuwärmen. Die Fußbodenheizungskurven wurden jeden Morgen leicht korrigiert, um die maximale Wärme (ca. 40 Grad im FB-Vorlauf) zu erreichen.<br />
<br />
Die Diagnose des "Stotterns" wurde zusammen mit einer Heizungsfirma als Theorie entwickelt, konnte jedoch nicht eindeutig belegt werden.<br />
<br />
Zum besseren Verständnis wurde zunächst die Verrohrung und die verwendeten Komponenten dokumentiert. Der Temperaturbegrenzer im Fußbodenkreis erwies sich als defekt und schaltete bei einer Konfiguration von 60°C bereits bei 40°C die Fußbodenpumpe ab.<br />
<br />
[[Datei:Morgennebel-HOWTO-Heizungsoptimierung-Anlagendiagramm.png|600px]]<br />
<br />
Laut Schornsteinfeger und Heizungsfirma war die Heizungsanlage selbst einwandfrei, jedoch war die Tetramatik-Steuerung mechanisch am Ende des Lebens. Die Abdeckungen fielen ab, das Hartplastik war versprödet, die Drehwiderstände für die Heizungskurven-Einstellung verstaubt.<br />
<br />
== Lösungsansatz ==<br />
Zur Verifizierung der Probleme und zum Aufbau eines Smart-Homes wurde fhem in der Kombination mit '''Homematic''' und '''1-Wire''' ausgewählt, da die ZWave-Experimente nicht sehr erfolgreich waren. Die vorhandene Tetramatik-Heizungssteuerung sollte auf ein Minimum beschränkt werden und die notwendige Intelligenz und Steuerung soweit wie möglich nach fhem verlagert werden.<br />
<br />
=== fhem und 1-Wire-Sensorik ===<br />
Zur Erhöhung des Verständnisses der Arbeitsweise der Heizung wurde als erster Schritt die verschiedenen Rück- und Vorläufe überwachst. Hierzu kam ein Rasberry Pi mit einem RPI3-Erweiterung von [http://www.sheepwalkelectronics.co.uk/product_info.php?products_id=67 Sheepwalk Electronics] in England zum Einsatz. Die RPI3-Erweiterung stellt 8 1-Wire-Bussysteme zur Verfügung. Zwei Busse werden direkt mit RJ45-Ports präsentiert, 6 weitere benötigen einen Bussplitter ([http://www.sheepwalkelectronics.co.uk/product_info.php?cPath=22&products_id=34 RPI3a] von Sheepwalk Eletronics) und stellen 1-Wire Busse als RJ45 oder Schraubverbindung zur Verfügung.<br />
<br />
Ebenfalls von Sheepwalk Eletronics kamen die passenden Sensoren ([http://www.sheepwalkelectronics.co.uk/product_info.php?cPath=23&products_id=52 SWE0], Typ DS18B20 mit 2m Anschlußkabel) zum Einsatz. <br />
<br />
Diese wurden liebevoll provisorisch (siehe Bild 2) an die entsprechenden Rohre verbunden und in fhem konfiguriert. In fhem waren dann mit Hilfe des [[Neues_Charting_Frontend]] aussagefähige Diagramme und Bewertungen über das Verhalten der Heizung möglich:<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-NachtAbsenkung+Taktung.jpg|mini|rechts|'''Bild 3''': Heizungstaktung mit Nachtabsenkung]]<br />
<br />
In der Konfiguration wurden alle Sensoren in fhem konfiguriert und auf 20 oder 60 Sekunden Abfrage konfiguriert:<br />
<br />
define EG.Heizung.Fussboden.Vorlauf OWDevice 28.A6E710050000 20<br />
attr EG.Heizung.Fussboden.Vorlauf IODev RPi1Wire<br />
attr EG.Heizung.Fussboden.Vorlauf model DS18B20<br />
attr EG.Heizung.Fussboden.Vorlauf room EG.HWR,OWDevice<br />
<br />
define EG.Heizung.Radiatoren.Vorlauf OWDevice 28.AD8A10050000 60<br />
attr EG.Heizung.Radiatoren.Vorlauf IODev RPi1Wire<br />
attr EG.Heizung.Radiatoren.Vorlauf model DS18B20<br />
attr EG.Heizung.Radiatoren.Vorlauf room EG.HWR,OWDevice<br />
<br />
Sehr deutlich ist in Bild 3 der korrekte Normalbetrieb der Heizung zu sehen: die Heizung taktet etwa alle 5 Minuten (in Abhängigkeit von der Außentemperatur und dem Verbrauch) mit einem An/Aus-Intervall. In der Zeit zwischen 22:00 und 5:00 ist eine Nachtabsenkung konfiguriert und die Kessel- und Vorlauftemperaturen kühlen ab. Nach der Nachtabsenkung sind die Taktlaufzeiten erheblich länger, bis die gewünschte Kessel- und Vorlauftemperatur wieder erreicht wird.<br />
<br />
Vor der Nachtabsenkung arbeitet der Mischer (orange Linie) korrekt, die Fußboden-Vorlauftemperatur schwankt im Rhythmus der Taktung des Brenners um einen Mittelwert von 35°C. Nach der Nachtabschaltung gibt es in der Fußboden-Vorlauftemperatur erhebliche Schwankungen: die Temperatur steigt kurzzeitig bis auf 48°C, was zur Abschaltung der Fußboden-Pumpe führt. Nach Abkühlung des Vorlaufes wird die Pumpe wieder eingeschaltet, erzeugt wieder eine Spitze und wird wieder abgeschaltet - der Mischer wird nicht vorbeugend zurückgefahren und langsam geöffnet.<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-Taktung.png|mini|rechts|'''Bild 4''': Funktionierende Mischung für Fußboden]]<br />
<br />
Bild 4 zeigt im Detail die Temperaturen der Radiatoren und des Fußbodenmischers: die oberste rote Kurve zeigt Temperatur des Fußbodenkreises vor dem Mischer (deutlich die Taktung des Brenners zu erkennen). Die gelbe und lila Kurve zeigen die Fußboden-Verlauftemperaturen nach dem Mischer an zwei verschiedenen Positionen, die blauen unteren Linien sind die Rücklauftemperaturen vom Fußbodenmischer und zurück zum Kessel.<br />
<br />
In diesem Beispiel arbeitet die Heizung korrekt ohne zu stottern.<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-Fussbodenmischer-stottern.png|mini|rechts|'''Bild 5''': Stotternde Fußbodenmischung]]<br />
<br />
In Bild 5 arbeitet die Mischersteuerung fehlerhaft und zu heißes Wasser im Vorlauf führt zum abschalten der Fußbodenpumpe. Es dauert bis zu 90 Minuten, bis die Temperatur abgesunken ist, die Pumpe erneut startet, und wieder abgeschaltet wird. Die Viessmann Tetramatik arbeitet hier nicht korrekt und führt den Mischer nicht zurück.<br />
<br />
Mit diesen Diagrammen war der vermutete Fehler eindeutig bewiesen und wurde temporär durch tägliche Justierungen der Heizkurven umgangen.<br />
<br />
Das Graphing Frontend erwies sich als extrem langsam und ressourcenhungrig. Als erste Schritt wurde das Logging in die sqllite-Datenbank minimiert, als zweiter Schritt ein zusätzliches Frontend auf Basis eines [http://www.hardkernel.com/main/products/prdt_info.php?g_code=g138745696275 ODROID U3] Boards verbaut. Dieses bietet 1.7GHz Quad-Core CPU und 2GB RAM für knapp 50 EUR und benötigt keinen Lüfter. Auch die 16GB eMMC-Speicherlösung verbesserte die Ansprechzeit deutlich. Der Raspberry Pi wurde auf die 8 1Wire-Bussysteme und -Sensoren beschränkt. Beide Boards wurden aus einem 4fach-USB-Ladegerät versorgt. Trotz der guten technischen Werte war das ODROID Board nicht in der Lage, MySQL als Datenbank zu verwenden - sqllite funktionierte jedoch leidlich.<br />
<br />
=== Heizungssteuerung (Radiatoren) ===<br />
Als nächster Schritt wurden häufig benutzte Räume mit Radiatoren mit [[HM-CC-RT-DN_Funk-Heizkörperthermostat|Homematic HM-CC-RT-DN Heizkörperthermostaten]] und [[HM-TC-IT-WM-W-EU_Funk-Wandthermostat_AP|Homematic HM-TC-IT-WM-W-EU Wandthermostaten]] versehen. Dies geschah schrittweise, etwa ein Raum je zwei Wochen. Die langsame Installation erlaubte es<br />
<br />
* Die Familie an den Gebrauch der Wandthermostaten zu gewöhnen<br />
* Die Lernzeit der Thermostaten und das Schwingverhalten auf einen Raum zu begrenzen<br />
* Die Kosten je Monat niedrig zu halten<br />
<br />
Die Fenster wurden mit [[HM-SEC-SC_Tür-Fensterkontakt|Fensterkontakten]] versehen und alle Geräte in fhem angelernt, untereinander gepeert und gepairt.<br />
<br />
Alle Thermostaten erhielten Wochenprofile auf der Basis von [[HomeMatic_HMInfo_TempList/Weekplan|Temperaturlisten]] namens 'tempList.cfg' im fhem-Verzeichnis. Die Wandthermostaten erlauben die Ermittlung der Raumfeuchte und sollen später für eine Lüftungsempfehlung genutzt werden.<br />
<br />
=== Heizungssteuerung (Fußboden) ===<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-FB-Alpha5.jpg|mini|rechts|''Bild 6'': Möhlenhoff Alpha-5 Stellantriebe]]<br />
<br />
Im Obergeschoß wurde die vorhandene UPONOR funkbasierende Lösung zur Steuerung der Fußbodenheizung zunächst entfernt. Die Uponor Ventile wurden durch [http://www.amazon.de/Stellantrieb-Buderus-Adapter-Oventrop-Bianchi/dp/B00K4UDS96 Alpha 5 Stellantriebe von Möhlenhoff] mit VA10-Adapter getauscht, die zu dem vorhandenen Fußbodenverteiler paßten. Die Alpha-5 Stellantriebe arbeiten mit 230V AC mit einer Leistungsaufnahme von 1W im Betrieb und sind nur als NC (normally-closed) Variante zu finden.<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-FB-230V-Steuerung.jpg|mini|rechts|''Bild 7'': Homematic 230V-Aktoren für Stellantriebe]]<br />
<br />
Um die Stellantriebe zu kamen zwei [[HM-LC-Sw4-DR_4fach_Schaltaktor_Hutschiene|Homematic 4fach Hutschienen Aktor]] und ein passendes Gehäuse in Aufputzvariante zum Einsatz. In allen Räumen wurden wieder mit [[HM-TC-IT-WM-W-EU_Funk-Wandthermostat_AP|Homematic HM-TC-IT-WM-W-EU Wandthermostaten]] versehen und als einfache Lösung zunachst die Aktoren mit dem '''_SwitchTr'''-Kanal verbunden.<br />
<br />
Das Rauchplastik-Gehäuse erlaubt eine wunderbare visuelle Kontrolle der Heizsituation im Obergeschoß.<br />
<br />
=== Einsparungen ===<br />
Im ersten Jahr nach Einbau der Funkthermostaten für Radiatoren in fünf Räumen und dem Wechsel der Steuerung der Fußbodenheizung im Obergeschoß wurde eine Verbrauchsreduzierung von '''20%''' gemessen. In Zahlen bedeutete dies eine Rückzahlung vom Gasanbieter in Höhe von gut 1.100 EUR sowie die Reduzierung der monatlichen Abschläge um 55 EUR. Auf ein Jahr gesehen wurden damit die Betriebskosten um 1.760 EUR reduziert, wobei Investitionen in Höhe von etwa 750 EUR für die Homematic-Komponenten, Raspberry und 1-Wire-Sensoren, HMLAN-Sender und Gehäuse und Kabel aufzubringen waren - d.h. es Gewinn von 1.010 EUR ohne Einrechnung der vielen Arbeitsstunden.<br />
<br />
Im zweiten Jahr wurden alle weiteren Radiatoren auf Homematic umgerüstet sowie die Fußbodenheizung im Erdgeschoß auf Homematic umgestellt. Durch diese Maßnahmen sind weitere Einsparungen abzusehen.<br />
<br />
=== STELLMOTOR Mischersteuerung ===<br />
Um das eindeutige identifizierte Stottern der Fußbodenheizung zu beheben, wurde der Fußbodenmischer auf eine Ansteuerung von fhem umgestellt. Für die Ansteuerung waren Relais notwendig, da der Mischermotor mit 230V, maximal 4A Anschlußwerten spezifiziert war. Zur Ansteuerung wurde daher ein 1-Wire 8fach Relaisboard von eBay [http://www.ebay.de/itm/1-Wire-8-Channel-Relay-Module-Board-with-Dallas-DS2408-chipset-/172063693628 Verkäufer leotron_87] in ein Verteilergehäuse eingebaut und mit dem vorhandenen 1-Wire-Bus verbunden.<br />
<br />
Das Relaisboard benötigt eine 12V-Spannungsversorgung und wurde von fhem problemlos erkannt:<br />
<br />
define EG.Heizung.8Relais OWDevice 29.3D5516000000<br />
attr EG.Heizung.8Relais IODev RPi1Wire<br />
attr EG.Heizung.8Relais model DS2408<br />
attr EG.Heizung.8Relais room EG.HWR,OWDevice<br />
<br />
mittels Kommandos wie <br />
<br />
set EG.Heizung.8Relais PIO.7 on<br />
set EG.Heizung.8Relais PIO.6 0<br />
<br />
konnten die einzelnen Relais angesteuert und geschaltet werden. Jedes Relais stellt NO (normally-open) und NC (normally-closed) Kontakte zur Verfügung und ist für verschiedene Spannungsbereiche (bei der Bestellung auszuwählen) freigegeben. Die gekaufte Variante unterstützte 7A bei 250V AC, so daß die maximale Anschlußleistung des Mischermotors kein Problem darstellte.<br />
<br />
Da der eBay-Verkäufer aus Bulgarien liefert, wurde eine zusätzliche Relaisplatine in die Ersatzteilkiste eingelagert.<br />
<br />
Der Mischermotor wurde nach Anleitung der [[STELLMOTOR|Stellmotor]] Anleitung im Schaltbild '''wechsel''' verbunden. Hierbei half eine Google-Suche nach einer Installationsanleitung des verbauten Viessmann-Mischers, welches die genauen Anschlußpläne beinhaltete. Bei Anschluß des Mischermotors ist ein 4- oder 5-poliges Installationskabel notwendig.<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-8fach-Relaiskarte.jpg|mini|rechts|''Bild 8'': Relaiskarte für Mischersteuerung und Stellantriebe]]<br />
<br />
Nach der abschliessenden Konfiguration des STELLMOTOR-Modules (Laufzeit, Relaisnamen):<br />
<br />
define EG.HWR.Fussbodenmischer STELLMOTOR FhemDev<br />
attr EG.HWR.Fussbodenmischer STMcalibrateDirection L<br />
attr EG.HWR.Fussbodenmischer STMdebugToLog3 0<br />
attr EG.HWR.Fussbodenmischer STMfhemDevRL EG.Heizung.8Relais PIO.6<br />
attr EG.HWR.Fussbodenmischer STMfhemDevSTART EG.Heizung.8Relais PIO.7<br />
attr EG.HWR.Fussbodenmischer STMinvertOut 0<br />
attr EG.HWR.Fussbodenmischer STMlastDiffMax 1<br />
attr EG.HWR.Fussbodenmischer STMmapOffCmd 0<br />
attr EG.HWR.Fussbodenmischer STMmapOnCmd 0<br />
attr EG.HWR.Fussbodenmischer STMmaxDriveSeconds 118<br />
attr EG.HWR.Fussbodenmischer STMmaxTics 100<br />
attr EG.HWR.Fussbodenmischer STMpollInterval 0.1<br />
attr EG.HWR.Fussbodenmischer STMresetOtherDeviceAtCalibrate 0<br />
attr EG.HWR.Fussbodenmischer STMrlType wechsel<br />
attr EG.HWR.Fussbodenmischer STMtimeTolerance 0.01<br />
attr EG.HWR.Fussbodenmischer room EG.HWR<br />
<br />
erfolgte der erste erfolgreiche Test durch<br />
<br />
set EG.HWR.Fussbodenmischer <Wert><br />
set EG.HWR.Fussbodenmischer cablibrate<br />
<br />
Das Ziel war eine Führung der Fußbodenvorlauftemperatur nahe an der maximal möglichen Temperatur (da sonst die oberen Räume zu kalt blieben). Für diese Steuerung waren zwei Schritte notwendig:<br />
<br />
# Ermittlung eines gleitenden Mittelwertes über die Fußbodenvorlauftemperatur (um kurzfristige Spitzen zu glätten)<br />
# Aufbau einer DOIF-Anweisung zur relativen Steuerung des Mischers<br />
<br />
Der gleitende Mittelwert wurde nach [[Gleitende_Mittelwerte_berechnen_und_loggen#Gleitender_Mittelwert_f.C3.BCr_beliebige_Readings|Anleitung]] in der 99_MyUtils.pm integriert und als Reading des bereits vorhandenen 1-Wire-Sensors integriert:<br />
<br />
define EG.Heizung.Mischer.Vorlauf OWDevice 28.3CD910050000 20<br />
attr EG.Heizung.Mischer.Vorlauf IODev RPi1Wire<br />
attr EG.Heizung.Mischer.Vorlauf model DS18B20<br />
attr EG.Heizung.Mischer.Vorlauf room EG.HWR,OWDevice<br />
attr EG.Heizung.Mischer.Vorlauf userReadings temperature.avg {movingAverage("EG.Heizung.Mischer.Vorlauf","temperature",300)}<br />
<br />
dies erzeugt das zusätzliche Reading '''temperature.avg''' für die Fußbodenvorlauftemperatur mit dem Mittel der letzten 5 Minuten.<br />
<br />
Die Regelung der Vorlauftemperatur selbst wurde über ein DOIF-Kommando erzeugt:<br />
<br />
define DI_MischerCommands DOIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] < 22 and [EG.HWR.Fussbodenmischer:position]<97 and [EG.Heizung.8Relais:PIO.3] eq "on")<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]+1)}) ## Cmd 1: Schnell oeffnen<br />
DOELSEIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] < 26 and [EG.HWR.Fussbodenmischer:position]<98 and [EG.Heizung.8Relais:PIO.3] eq "on")<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]+1)}) ## Cmd 2: Ganz langsam oeffnen<br />
DOELSEIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] < 30 and [EG.HWR.Fussbodenmischer:position]<98 and [EG.Heizung.8Relais:PIO.3] eq "on")<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]+1)}) ## Cmd 3: Noch ein bisschen<br />
DOELSEIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] > 35 and [EG.HWR.Fussbodenmischer:position]>3)<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]-2)}) ## Cmd 4: Viel zu heiss, schnell zu<br />
DOELSEIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] > 34 and [EG.HWR.Fussbodenmischer:position]>2)<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]-1)}) ## Cmd 5: Zu heiss, schnell zu<br />
DOELSEIF ([EG.Heizung.Mischer.Vorlauf:temperature.avg] > 33 and [EG.HWR.Fussbodenmischer:position]>2)<br />
(set EG.HWR.Fussbodenmischer {([EG.HWR.Fussbodenmischer:position]-1)}) ## Cmd 6: Noch ein bisschen<br />
DOELSEIF ([03:50])<br />
(set EG.HWR.Fussbodenmischer calibrate) ## Cmd 7: Calibrieren fuer Tagprogramm<br />
DOELSEIF ([04:00])<br />
(set EG.HWR.Fussbodenmischer 40) ## Cmd 8: Headstart, Ende der Nachtabsenkung<br />
attr DI_MischerCommands cmdpause 60:120:180:60:120:180:0:0<br />
attr DI_MischerCommands wait 180,240,300,180,240,480,0,0<br />
attr DI_MischerCommands do always<br />
<br />
Die in dieser '''individuellen''' Konfiguration ist die gewünschte Zieltemperatur der Fußbodenvorlauftemperatur zwischen 30° und 32°C (im fest verbauten Thermometer bedeutet dies knapp unter 40°C). Die Temperatur des Sensors (und des Mittelwertes) weicht jedoch von den eingebauten physikalischen Thermostaten ab. Vermutlich liegt das an der zusätzlichen Plastikabschirmung der Sensoren und der Dicke der Rohre - die Zieltemperaturen wurden daher durch Try-n-Error ermittelt.<br />
<br />
Die ersten drei IF-Bedingungen öffnen den Mischer (erhöhen die Fußboden-Vorlauftemperatur). Die folgenden drei IF-Bedingungen schließen den Mischer (verringern die Fußboden-Vorlauftemperatur). Die letzten beiden Anweisungen kalibrieren morgens den Mischer und sorgen für einen schnelleren Start.<br />
<br />
Jede der drei öffnenden IF-Bedingungen sind auf leicht unterschiedliche Temperaturen nahe der Zieltemperatur (zwischen 30-32 Grad) eingestellt. Eine Justierung der Öffnungsgeschwindigkeit findet über die Attribute wait und cmdpause statt: ist die Temperatur weit von der Zieltemperatur entfernt, wird kurz gewartet und der Mischer beliebig oft geöffnet. Ist die Temperatur nahe der Zieltemperatur, wird sich langsam und vorsichtig an das Ziel herangetastet - das Attribut wait steuert die Wartezeit und cmdpause verhindert ein überschwingen.<br />
<br />
Jede drei schließenden IF-Bedingungen sind analog aufgebaut, jedoch wird die Temperatur schnell reduziert, um das stottern und den Abkühlprozeß zu vermeiden. <br />
<br />
Die Kalibrierung und ein Frühstart finden morgens statt. In der ersten öffnenden IF-Bedingung wurde zusätzlich die Abfrage '''[EG.Heizung.8Relais:PIO.3] eq "on"''' integriert. Diese prüft, ob die Fußbodenpumpe aktiv ist oder wegen zu hohen Vorlauftemperaturen deaktiviert wurde. Dies verhindert ein Überschwingen im Zusammenspiel mit dem thermischen Maximalbegrenzer - die Abkühlzeit ist so hoch, daß der Mischer bereits wieder den Mischer öffnet um die Temperatur zu erhöhen. Schaltet dann die Pumpe ein, überschreitet die Vorlauftemperatur wieder sofort das Maximum.<br />
<br />
Das DOIF-Kommando führt zu folgenden Meßwerten:<br />
<br />
[[Datei:Morgennebel-HeizungssteuerungHOWTO-Mischer1Tag.png]]<br />
<br />
Die Nachtabsenkung endet um 4:00, gleichzeitig startet die Kalibrierung (setzt den Mischer auf 0). Der Mischer (blaue Linie) öffnet schnell, überschwingt leicht und regelt sich dann auf eine sehr gerade Kennlinie mit beinahe konstanter Temperatur zurück.<br />
<br />
Nach einer Woche Betrieb stellte sich heraus, daß die Viessmann Tetramatik die Fußbodenpumpe dauerhaft abstellte. Offenbar (und vielleicht) erkennt die Tetramatik, daß diese den Mischer nicht mehr kontrollieren kann und stellt zur Sicherheit die Pumpe ab.<br />
<br />
Daher wurde auch die Pumpe an den 8-fach Relaiskarte via 1-Wire geschaltet und mit Hilfe einer DOIF-Anweisung gesteuert:<br />
<br />
define DI_EG.HWR.Fussbodenpumpe DOIF ([04:00-23:00] and [EG.Heizung.Mischer.Vorlauf:temperature] < 33)<br />
(set EG.Heizung.8Relais PIO.3 on) <br />
DOELSE <br />
(set EG.Heizung.8Relais PIO.3 off) <br />
attr DI_EG.HWR.Fussbodenpumpe room EG.HWR <br />
attr DI_EG.HWR.Fussbodenpumpe wait 0,900 <br />
<br />
die Erkennung der Maximaltemperatur mit einer 15 minütigen Abkühlphase erlaubte die Deaktivierung des Thermostaten zur Begrenzung des Fußbodenvorlaufes (siehe Diagramm in der Einleitung).<br />
<br />
=== Kombinierte Fußbodens- und Radiatorenheizung ===<br />
In den Räumen mit kombinierter Fußboden- und Radiatorenheizung wird der Fußbodenkreis über ein DOIF-Kommando gesteuert, welches auf den Öffnungswert (actuator-Stand) der Radiatorheizung triggert:<br />
<br />
define DI_EG.Wintergarten.Fussbodenheizung DOIF ([EG.Wintergarten.Heizung:actuator] > 10)<br />
(set EG.Heizung.8Relais PIO.0 on)<br />
DOELSE<br />
(set EG.Heizung.8Relais PIO.0 off)<br />
attr DI_EG.Wintergarten.Fussbodenheizung wait 180,1800<br />
<br />
In diesem Beispiel wird der Alpha 5 Stellantrieb über die 8fach Relaiskarte an '''PIO.0''' (siehe Abschnitt fhem-Erweiterungen und STELLMOTOR) angesteuert. Das DOIF-Kommando aktiviert die Fußbodenheizung, wenn die Radiatoren länger als drei Minuten mit mehr als 10 (10%) heizen und läßt diese dann mindestens 30 Minuten aktiviert.<br />
<br />
Sollten mehrere Heizungen im Raum vorhanden sein, läßt sich dies durch den Mittelwert der Aktuatorenstellung mit Hilfe einer perl-Anweisung lösen.<br />
<br />
Damit folgt die Fußbodenheizung automatisch den Wochenprofilen des Wandthermostaten im Wintergarten bzw. dessen Heizungsverhalten bei manueller Übersteuerung oder der Erkennung von offenen Fenstern.<br />
<br />
=== Bedarfsgesteuerte Kontrolle der Fußbodenumwälzpumpe ===<br />
Zur weiteren Verbrauchsoptimierung sollte nun die Fußbodenumwälzpumpe bedarfsgerecht ein- und wieder ausgeschaltet werden. Wie in der Einführung beschrieben hat diese einen konstanten Verbrauch von 170W/h, so daß die Reduzierung der Laufzeit schnell erhebliche Einsparungen verspricht.<br />
<br />
Im ersten Schritt wird ein Dummy definiert, der den '''Bedarf''' an warmen Heizwasser reflektiert. Diese Dummy-Variable wird minütlich durch ein DOIF-Kommando belegt:<br />
<br />
define D_EG.HWR.FussbodenAnforderung dummy<br />
attr D_EG.HWR.FussbodenAnforderung room EG.HWR<br />
<br />
define DI_EG.HWR.FussbodenpumpeAnforderung DOIF ([+0:01] and <br />
([?OG.Flur.Fussboden.Links_Sw_FBChild1Arbeitszimmer] eq "on" or <br />
[?OG.Flur.Fussboden.Links_Sw_FBChild1Schlafzimmer] eq "on" or<br />
[?OG.Flur.Fussboden.Links_Sw_FBChild2Links] eq "on" or<br />
[?OG.Flur.Fussboden.Links_Sw_FBChild2Rechts] eq "on" or<br />
[?OG.Flur.Fussboden.Rechts_Sw_FBBadLinks] eq "on" or<br />
[?OG.Flur.Fussboden.Rechts_Sw_FBBadRechts] eq "on" or<br />
[?OG.Flur.Fussboden.Rechts_Sw_FBFlur] eq "on"))<br />
(set D_EG.HWR.FussbodenAnforderung on)<br />
DOELSE<br />
(set D_EG.HWR.FussbodenAnforderung off)<br />
attr DI_EG.HWR.FussbodenpumpeAnforderung wait 300,1800<br />
attr DI_EG.HWR.FussbodenpumpeAnforderung room EG.HWR<br />
<br />
Da sich die verwendeten Wandthermostaten alle 2.5 Minuten bei fhem melden, ist der Versatz in Durchschnitt etwa 180 Sekunden. Die im DOIF abgefragten Konditionen sind die verschiedenen 230V-Schaltaktoren, welche die Ventilantriebe ansteuern. Fordert auch nur ein Kreis Wärme an, wird der Dummy auf '''on''' gesetzt - damit folgt der Dummy allen Wochenprofilen der verschiedenen Wandthermostaten oder auch allen manuellen Änderungen.<br />
<br />
Die bereits vorhandene DOIF-Anweisung zur Kontrolle der Fußbodenpumpe wurde um den Zustand des Dummys erweitert:<br />
<br />
define DI_EG.HWR.Fussbodenpumpe DOIF ([04:00-21:00] and [EG.Heizung.Mischer.Vorlauf:temperature] < 34 and [D_EG.HWR.FussbodenAnforderung] eq "on")<br />
(set EG.Heizung.8Relais PIO.3 on)<br />
DOELSE<br />
(set EG.Heizung.8Relais PIO.3 off)<br />
attr DI_EG.HWR.Fussbodenpumpe wait 0,45<br />
attr DI_EG.HWR.Fussbodenpumpe room EG.HWR<br />
<br />
Damit wird die Fußbodenpumpe zwischen 4 Uhr (Ende der Nachtabschaltung) bis 21 Uhr aktiviert, sofern die Mischervorlauftemperatur nicht zu hoch wird und tatsächlich Wärme benötigt wird.<br />
<br />
Zur Kontrolle der Einsparungen wurde noch zusätzlich das Modul [[HourCounter]] konfiguriert:<br />
<br />
define HC_EG.HWR.Fussbodenpumpe HourCounter EG.Heizung.8Relais:PIO.3:.on EG.Heizung.8Relais:PIO.3:.off<br />
attr HC_EG.HWR.Fussbodenpumpe room EG.HWR<br />
<br />
In den Readings des HourCounters '''pauseTimePerDay''' zeigt dann die Summe der Ausschaltzeit pro Tag ein, rechnet jedoch auch die vier Stunden (Mitternacht bis 4 Uhr) bis zum Beginn der Tagesheizperiode ein.<br />
<br />
Als Diagramm ergibt sich diese Darstellung:<br />
<br />
[[Datei:Morgennebel-HOWTO-Heizungsoptimierung-Pumpensteuerung.png]]<br />
<br />
Nach der Nachtabsenkung wird die Fußbodenvorlauftemperatur auf die gewünschten 30-33°C Grad (am Meßpunkt, entspricht 40°C im fest eingebauten Thermometer) gesteuert. Kurz nach 12 Uhr ist der Bedarf an Fußbodenwärme gedeckt und die Umwälzpumpe wird deaktiviert. Dieser Zustand hält knapp 8 Stunden an, bis kurz nach 20:30 Uhr wieder Wärme angefordert wird. Jedoch greift um 21:30 schon die Nachtabschaltung der Heizung selbst.<br />
<br />
Am Tag davor tobte ein Sturm über das Haus und der kalte Wind sorgte für eine Abkühlung in den Räumen:<br />
<br />
[[Datei:Morgennebel-HOWTO-Heizungsoptimierung-PumpensteuerungSturm.png]]<br />
<br />
Der Wärmebedarf war erheblich höher und als Folge blieb die Pumpe dauerhaft an.<br />
<br />
=== Gaszähler ===<br />
Nachdem die Räume vollständig geregelt und mit Wochenprofilen versehen waren, wurde die Messung des Gasverbrauches aufgebaut. Mit Hilfe der Verbrauchsdaten sowie der '''Zustandszahl''' und des '''Brennwertes''' (beides beim Gasversorger zu erfragen) läßt sich der Verbrauch an kWh errechnen.<br />
<br />
Zur Messung des Gasverbrauches wurde der [[HM-EM-TX-WM_Zählersensor_für_Strom-_und_Gaszähler|Homematic Bausatz zur Strom- und Gasmessung]] verwendet. Der von ELV gelieferte Gaszähler paßte mechanisch nicht in den vorhanden ''iTron G4 RF1-MM'' Gaszähler. Der ELV-Gaszähler besteht aus einer kleinen Schaltung mit wenigen Widerständen und einem Reed-Schalter - da eine exakte Messung wichtig war, wurde von [http://www.world-of-heating.de/ World of Heating] der passende Impulsnehmer GMT Typ 951-858-06 nachbestellt und in die Schaltung von ELV eingelötet. Der Impulsnehmer kommt mit langen Anschlußkabeln und läßt sich sehr einfach einbauen.<br />
<br />
Nach der Konfiguration des [[HM-EM-TX-WM_Zählersensor_für_Strom-_und_Gaszähler|Homematic Bausatzes]] auf die vom Gaszähler gelieferten Impulse je Einheit lieferte dieser zuverlässig die Verbrauchsdaten. Diese lassen sich schnell und einfach visualisieren.<br />
<br />
[[Datei:Morgennebel-HOWTO-Heizungsoptimierung-Gasverbrauch.png]]<br />
<br />
Zusammen mit der Außentemperatur und der Uhrzeit sollen diese dann als Grundlage zur Dimensionierung einer neuen Heizungsanlage verwendet werden. Dazu werden die Logdateien der Außentemperatur und der Verbrauch an Gas auf die Stunde umgerechnet. Die vorhandenen Meßpunkte können dann in eine Verbrauchskurve in Abhängigkeit der Außentemperatur überführt werden - und da alle Räume wie gewünscht warm werden, stellt dies dann die notwendige Dimensionierung der neuen Heizung dar.<br />
<br />
[[Kategorie:Examples]]<br />
[[Kategorie:Heizungssteuerung]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Kategorie:Heizungssteuerung&diff=16527Kategorie:Heizungssteuerung2016-10-06T07:29:17Z<p>Fabian: Querverweis zu Heizungsventilen angepasst, Querverweis zu neuem Grundlage-Artikel erstellt</p>
<hr />
<div>In dieser Kategorie werden sowohl die integrierten Steuerungen der Wärmequellen einer Heizungs- und Warmwasseranlage als auch die intelligenten Heizungsthermostate zur Steuerung der Heizungsventile erfasst.<br />
<br />
Intelligente Heizkörperventile werden in der [[:Kategorie:Heizungsventile]] aufgelistet.<br />
<br />
; Eine grundsätzliche Betrachtung von Möglichkeiten zur Heizungssteuerung findet sich [[Grundlagen der Heizungssteuerung|hier]].<br />
<br />
[[Kategorie:Hardware Typen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Kategorie:Heizungsventile&diff=16525Kategorie:Heizungsventile2016-10-06T07:24:49Z<p>Fabian: Kurze Einführung und Verlinkung zu Heizungssteuerung eingetragen</p>
<hr />
<div>In dieser Kategorie werden verschiedene steuerbare Heizungsventile aufgelistet.<br />
<br />
Artikel zum Thema Heizungssteuerung finden sich in der [[:Kategorie:Heizungssteuerung]].<br />
<br />
[[Kategorie:Hardware Typen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=FileLog&diff=16482FileLog2016-10-03T16:45:12Z<p>Fabian: /* Werte auslesen */</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokollierung von Fhem-Ereignissen<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=92_FileLog.pm<br />
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])}}<br />
<br />
Das Modul [[FileLog]] dient zur Protokollierung von Ereignissen in Fhem. Die Einträge werden in eine einfache Textdatei geschrieben. Zur Protokollierung in eine Datenbank kann alternativ oder auch parallel das Modul [[DbLog]] verwendet werden.<br />
<br />
Logdateien sind die Basis für die Erstellung von Diagrammen ([[SVG]]).<br />
<br />
<br />
== Definition ==<br />
Details in der commandref (siehe Infobox).<br />
<br />
<br />
== Attribute ==<br />
Über Attribute lässt sich unter anderem auch festlegen, wie die Archivierung von Logdateien durchgeführt werden soll (Archivierungsbefehl, -pfad sowie Anzahl von Archivgenerationen).<br />
<br />
<br />
== Funktionen ==<br />
''FileLog'' bietet Funktionen wie ''reopen'', ''absorp'' und ''get''. Details dazu sind in der commandref (siehe Infobox) zu finden.<br />
<br />
Sofern eine Instanz vom Objekt [[eventTypes]] angelegt ist, bietet die Detailansicht eines FileLog eine komfortable Möglichkeit, die regulären Ausdrücke für den/die Filter zu bearbeiten. Siehe hierzu auch diesen {{Link2Forum|Topic=12557|Message=75436}}.<br />
<br />
<br />
== Globale Logdatei und "fakelog" ===<br />
Die globale Logdatei (üblicherweise als fhem.log bezeichnet) für Fhem wird mit dem Attribut <br />
:<code>attr global logfile XXX</code><br />
für das ''global''-Objekt definiert, wobei für ''XXX'' normalerweise <code>./log/fhem-%Y-%m.log</code> verwendet wird.<br />
<br />
Um das ''fhem.log'' über das [[FHEMWEB|Web Interface]] anzeigen zu können, ist ein weiterer Eintrag in der [[Konfiguration]] erforderlich, nämlich:<br />
:<code>define Logfile FileLog XXX fakelog</code><br />
Das ''XXX'' muss '''zwingend''' durch den gleichen Wert ersetzt werden, wie in der Definition des globalen ''logfile'' Attributs, weil anderenfalls unterschiedliche Dateien verwendet werden - mit dem Effekt, dass die über das Web Interface angezeigte Datei nicht die erwarteten Einträge enthält (Details dazu auch in diesem {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}}).<br />
<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in den Logfiles herumzuwühlen. Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der [http://fhem.de/commandref_DE.html#FileLog commandref#FileLog] und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[DbLog#Werte_auslesen|DbLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get FileLog_FHT_3a32 - - 2016-10-01 2016-10-03</code> alle Einträge des FileLog_FHT_3a32 vom 01.10.-03.10.2016<br />
* <code>get FileLog_FHT_3a32 - - 2016-10-01_08:00:00 2016-10-01_16:00:00</code> alle Einträge des FileLog_FHT_3a32 von 8-16 Uhr am 01.10.2016<br />
* <code>get FileLog_FHT_3a32 - - 2016-10-01_08:00:00 2016-10-01_16:00:00 4:measured:0:</code> nur die Temperatur-Werte<br />
* <code>{ ReadingsTimestamp("FHT_3a32","state","0") }</code> Timestamp des aktuellen state des FHT_3a32<br />
* <code>{ OldTimestamp("FHT_3a32") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("FHT_3a32")) }</code> Timestamp in Sekunden des letzten state des FHT_3a32<br />
* ...<br />
Weitere Beispiele kann man sich gut aus den SVG-Dateien ziehen.<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}} zum Thema fhem.log / fakelog</div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=16481DbLog2016-10-03T16:38:01Z<p>Fabian: /* Werte auslesen */</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />
}}<br />
<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen im fhem recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als [http://fhem.de/commandref_DE.html#FileLog FileLog] gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann Fhem die Log-Daten mittels [http://fhem.de/commandref_DE.html#DbLog DbLog] in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es 2 Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. [http://fhem.de/commandref_DE.html#event-on-update-reading commandref])<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe commandref.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
* current<br />
* history<br />
<br />
<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen.<br />
<br />
=== Tabellenlayout ===<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [http://sourceforge.net/p/fhem/code/HEAD/tree/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Unter Ubuntu: <br />
apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
<br />
nun zu mysql verbinden:<br />
mysql -p -u root<br />
Enter password:<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann nach Bedarf in der Datei /opt/fhem/contrib/dblog/db_create_mysql.sql das Passwort und der Benutzername geändert werden.<br />
Dann wird die Datei eingelesen: <br />
<br />
#mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
#mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
vim /opt/fhem/contrib/dblog/db.conf<br />
<br />
Jetzt kann ein DbLog-Device angelegt werden: <br />
define logdb DbLog ./contrib/dblog/db.conf .*:.* # loggt ALLES!<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in Fhem stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<source lang="sql"><br />
#mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from current; # Achtung, kann sehr groß werden .... #<br />
</source><br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_SplitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
Weitere Informationen siehe hier: [[DevelopmentModuleIntro#X_DbLog_splitFn]]<br />
<br />
<br />
== Bekannte Probleme ==<br />
Beim Anlegen der Datenbank per script wird die Value-Spalte nur als Varchar(32) definiert. Dieses kann dazu führen, dass besonders lange Readings (z.b. vom Modul sysmon) abgeschnitten werden und nicht in der Datenbank landen. Dieses lässt sich leicht beheben, indem man die Spalte auf Varchar(64) ändert (siehe auch {{Link2Forum|Topic=25648|Message=252433|LinkText=diesen Forenbeitrag}}).<br />
<br />
mysql> ALTER TABLE current MODIFY VALUE VARCHAR(64);<br />
mysql> ALTER TABLE history MODIFY VALUE VARCHAR(64);<br />
<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in der Datenbank herumzuwühlen (s.u.). Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der [http://fhem.de/commandref_DE.html#DbLog commandref#DbLog] und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor den fhem ausmacht um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden ohne den fhem abschalten zu müssen. <br />
<br />
Datenbanken kann man ohne weiter Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt fhem stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
fhem wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
=== Dateigroesse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Groesse taetig zu werden. Dazu muss diese Groesse alledings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:lastReduceLogResult.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Groesse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=16480DbLog2016-10-03T16:36:46Z<p>Fabian: Kap. "Werte auslesen" erstellt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />
}}<br />
<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen im fhem recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als [http://fhem.de/commandref_DE.html#FileLog FileLog] gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann Fhem die Log-Daten mittels [http://fhem.de/commandref_DE.html#DbLog DbLog] in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es 2 Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. [http://fhem.de/commandref_DE.html#event-on-update-reading commandref])<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe commandref.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
* current<br />
* history<br />
<br />
<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen.<br />
<br />
=== Tabellenlayout ===<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [http://sourceforge.net/p/fhem/code/HEAD/tree/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Unter Ubuntu: <br />
apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
<br />
nun zu mysql verbinden:<br />
mysql -p -u root<br />
Enter password:<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann nach Bedarf in der Datei /opt/fhem/contrib/dblog/db_create_mysql.sql das Passwort und der Benutzername geändert werden.<br />
Dann wird die Datei eingelesen: <br />
<br />
#mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
#mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
vim /opt/fhem/contrib/dblog/db.conf<br />
<br />
Jetzt kann ein DbLog-Device angelegt werden: <br />
define logdb DbLog ./contrib/dblog/db.conf .*:.* # loggt ALLES!<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in Fhem stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<source lang="sql"><br />
#mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from current; # Achtung, kann sehr groß werden .... #<br />
</source><br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_SplitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
Weitere Informationen siehe hier: [[DevelopmentModuleIntro#X_DbLog_splitFn]]<br />
<br />
<br />
== Bekannte Probleme ==<br />
Beim Anlegen der Datenbank per script wird die Value-Spalte nur als Varchar(32) definiert. Dieses kann dazu führen, dass besonders lange Readings (z.b. vom Modul sysmon) abgeschnitten werden und nicht in der Datenbank landen. Dieses lässt sich leicht beheben, indem man die Spalte auf Varchar(64) ändert (siehe auch {{Link2Forum|Topic=25648|Message=252433|LinkText=diesen Forenbeitrag}}).<br />
<br />
mysql> ALTER TABLE current MODIFY VALUE VARCHAR(64);<br />
mysql> ALTER TABLE history MODIFY VALUE VARCHAR(64);<br />
<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in den Logfiles herumzuwühlen. Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der [http://fhem.de/commandref_DE.html#DbLog commandref#DbLog] und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor den fhem ausmacht um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden ohne den fhem abschalten zu müssen. <br />
<br />
Datenbanken kann man ohne weiter Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt fhem stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
fhem wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
=== Dateigroesse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Groesse taetig zu werden. Dazu muss diese Groesse alledings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:lastReduceLogResult.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Groesse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=FileLog&diff=16479FileLog2016-10-03T15:52:06Z<p>Fabian: Kap. "Werte auslesen" erstellt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokollierung von Fhem-Ereignissen<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=92_FileLog.pm<br />
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])}}<br />
<br />
Das Modul [[FileLog]] dient zur Protokollierung von Ereignissen in Fhem. Die Einträge werden in eine einfache Textdatei geschrieben. Zur Protokollierung in eine Datenbank kann alternativ oder auch parallel das Modul [[DbLog]] verwendet werden.<br />
<br />
Logdateien sind die Basis für die Erstellung von Diagrammen ([[SVG]]).<br />
<br />
<br />
== Definition ==<br />
Details in der commandref (siehe Infobox).<br />
<br />
<br />
== Attribute ==<br />
Über Attribute lässt sich unter anderem auch festlegen, wie die Archivierung von Logdateien durchgeführt werden soll (Archivierungsbefehl, -pfad sowie Anzahl von Archivgenerationen).<br />
<br />
<br />
== Funktionen ==<br />
''FileLog'' bietet Funktionen wie ''reopen'', ''absorp'' und ''get''. Details dazu sind in der commandref (siehe Infobox) zu finden.<br />
<br />
Sofern eine Instanz vom Objekt [[eventTypes]] angelegt ist, bietet die Detailansicht eines FileLog eine komfortable Möglichkeit, die regulären Ausdrücke für den/die Filter zu bearbeiten. Siehe hierzu auch diesen {{Link2Forum|Topic=12557|Message=75436}}.<br />
<br />
<br />
== Globale Logdatei und "fakelog" ===<br />
Die globale Logdatei (üblicherweise als fhem.log bezeichnet) für Fhem wird mit dem Attribut <br />
:<code>attr global logfile XXX</code><br />
für das ''global''-Objekt definiert, wobei für ''XXX'' normalerweise <code>./log/fhem-%Y-%m.log</code> verwendet wird.<br />
<br />
Um das ''fhem.log'' über das [[FHEMWEB|Web Interface]] anzeigen zu können, ist ein weiterer Eintrag in der [[Konfiguration]] erforderlich, nämlich:<br />
:<code>define Logfile FileLog XXX fakelog</code><br />
Das ''XXX'' muss '''zwingend''' durch den gleichen Wert ersetzt werden, wie in der Definition des globalen ''logfile'' Attributs, weil anderenfalls unterschiedliche Dateien verwendet werden - mit dem Effekt, dass die über das Web Interface angezeigte Datei nicht die erwarteten Einträge enthält (Details dazu auch in diesem {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}}).<br />
<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in den Logfiles herumzuwühlen. Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der [http://fhem.de/commandref_DE.html#FileLog commandref#FileLog].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get FileLog_FHT_3a32 - - 2016-10-01 2016-10-03</code> alle Einträge des FileLog_FHT_3a32 vom 01.10.-03.10.2016<br />
* <code>get FileLog_FHT_3a32 - - 2016-10-01_08:00:00 2016-10-01_16:00:00</code> alle Einträge des FileLog_FHT_3a32 von 8-16 Uhr am 01.10.2016<br />
* <code>{ ReadingsTimestamp("FHT_3a32","state","0") }</code> Timestamp des aktuellen state des FHT_3a32<br />
* <code>{ OldTimestamp("FHT_3a32") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("FHT_3a32")) }</code> Timestamp in Sekunden des letzten state des FHT_3a32<br />
* ...<br />
<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}} zum Thema fhem.log / fakelog</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Batterie%C3%BCberwachung&diff=16476Batterieüberwachung2016-10-03T13:38:30Z<p>Fabian: Gesamten Artikel abgerundet</p>
<hr />
<div>Verschiedene batteriebetriebene Geräte ([[:Kategorie:HomeMatic Components|Homematic]],RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Bei diesen kann der Batteriestatus übersichtlich dargestellt u/o aktiv überwacht werden. Bei Geräten ohne eigenen Batteriestatus muss man diesen "nachrüsten".<br />
<br />
<br />
== Geräte mit Batteriestatus ==<br />
<br />
=== Übersichtsdarstellung per readingsGroup ===<br />
Mit Hilfe einer ReadingsGroup kann einfach eine Übersicht aller Geräte mit "battery"-Reading erstellt werden, s. [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|hier]].<br />
<br />
<br />
=== Benachrichtigung per notify ===<br />
Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME : Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
'''Achtung:''' Für Nutzer eines [[HM-CC-RT-DN_Funk-Heizk%C3%B6rperthermostat|HM-CC-RT-DN]] muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:<br />
<br />
UG.Treppe.Heizung batteryLevel: 3.1 V<br />
<br />
Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME: Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel [[E-Mail_senden]] beschrieben.<br />
<br />
Testen kann man dies z.B. mit <code>trigger HeizungWZ Battery:low</code><br />
<br />
Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut <code>event-on-change-reading</code>).<br />
<br />
<br />
<br />
== Geräte ohne Batteriestatus ==<br />
<br />
=== Erweiterung des Geräts um battery-Reading ===<br />
<br />
Mit Hilfe von [http://fhem.de/commandref_DE.html#userReadings userReadings] kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.<br />
<br />
Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.<br />
<br />
Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen): <br />
<br />
'''Anzupassen''' ist nur der Schwellwert (600), alles andere passt automatisch (vgl. [http://www.fhemwiki.de/wiki/Notify#Hinweise]).<br />
<br />
Im Webinterface:<br />
<pre><br />
battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }<br />
</pre><br />
<br />
Alternativ im Config-File:<br />
<pre><br />
attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>battery {...}</code> - Name des userreadings mit Spezifikation, vgl. [http://fhem.de/commandref_DE.html#userReadings]<br />
: <code>return "ok" if ( ... );; return "low"</code> - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"<br />
: <code>time_str2num(ReadingsTimestamp($NAME,"state","0")</code> - Aktueller Timestamp in Sekunden, vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>time_str2num(OldTimestamp($NAME))</code> - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>600</code> - Schwellwert für "low" (600 sec = 10 min)<br />
<br />
<br />
=== Alternativ per Skript ===<br />
<br />
Andere Komponenten, wie z. B. [[:Kategorie:FS20 Components|FS20 Komponenten]], übermitteln keinen Batteriestatus. <br />
<br />
Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in [[99_myUtils_anlegen|99_myUtils.pm]]:<br />
<br />
<pre>sub check_if_alive($$) {<br />
# Expects:<br />
# 1. Devicename to be checked<br />
# 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.<br />
# Returns:<br />
# 0 -> Device dead<br />
# 1 -> Device alive<br />
# 2 -> Error<br />
my ($Device,$hours_threshold) = @_;<br />
my ($Device) = @_;<br />
my $now = time;<br />
my $Timestamp = ReadingsTimestamp($Device,"state","0");<br />
if ($Timestamp eq "0") {<br />
return 2;<br />
}<br />
<br />
my @splitdatetime = split(/ /,$Timestamp);<br />
my @splitdate = split(/-/, $splitdatetime[0]);<br />
my @splittime = split(/:/, $splitdatetime[1]);<br />
my $last_state_time = timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);<br />
my $age_in_hours = ($now - $last_state_time) / 3600;<br />
<br />
if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
return 0;<br />
} else {<br />
return 1;<br />
}<br />
<br />
}</pre><br />
<br />
Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:<br />
<br />
<pre>*05:55:55 { <br />
check_if_alive("KS300", 12);<br />
}</pre><br />
<br />
KS300 ist dabei der Name des Devices in fhem. <br />
<br />
Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.<br />
<br />
Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.<br />
<br />
=== Visualisierung ===<br />
<br />
Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.<br />
<br />
Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:<br />
<br />
<pre>Internals: <br />
NAME dum_KS300_dead <br />
NR 795 <br />
STATE nein <br />
TYPE dummy <br />
Readings: <br />
2015-04-28 07:47:48 state nein <br />
Attributes: <br />
devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green</pre><br />
<br />
Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie. <br />
<br />
Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:<br />
<br />
<pre> if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
fhem("set dum_".$Device."_dead ja");<br />
return 0;<br />
} else {<br />
fhem("set dum_".$Device."_dead nein");<br />
return 1;<br />
}</pre><br />
<br />
Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.<br />
<br />
== Links ==<br />
<br />
* [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|visuelle Batterieüberwachung mit readingsGroup]]<br />
* [http://fhem.de/commandref_DE.html#userReadings commandref - userReadings]<br />
* [http://fhem.de/commandref_DE.html#perl commandref - Perl specials]<br />
* [[Notify#Hinweise|Hinweise zu Variablen]] (ansonsten auch an div. Stellen in der [http://fhem.de/commandref_DE.html commandref])<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Hardware]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Batterie%C3%BCberwachung&diff=16475Batterieüberwachung2016-10-03T13:20:39Z<p>Fabian: /* Geräte mit Batteriestatus */ Übersicht per readingsGroup ergänzt</p>
<hr />
<div>== Geräte mit Batteriestatus ==<br />
<br />
=== Übersichtsdarstellung per readingsGroup ===<br />
Mit Hilfe einer ReadingsGroup kann einfach eine Übersicht aller Geräte mit "battery"-Reading erstellt werden, s. [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|hier]].<br />
<br />
<br />
=== Benachrichtigung per notify ===<br />
<br />
[[:Kategorie:HomeMatic Components|Homematic-Komponenten]] und teilweise andere Komponenten (RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME : Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
'''Achtung:''' Für Nutzer eines [[HM-CC-RT-DN_Funk-Heizk%C3%B6rperthermostat|HM-CC-RT-DN]] muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:<br />
<br />
UG.Treppe.Heizung batteryLevel: 3.1 V<br />
<br />
Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME: Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel [[E-Mail_senden]] beschrieben.<br />
<br />
Testen kann man dies z.B. mit <code>trigger HeizungWZ Battery:low</code><br />
<br />
Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut <code>event-on-change-reading</code>).<br />
<br />
== Geräte ohne Batteriestatus ==<br />
<br />
=== Erweiterung des Geräts um battery-Reading ===<br />
<br />
Mit Hilfe von [http://fhem.de/commandref_DE.html#userReadings userReadings] kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.<br />
<br />
Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.<br />
<br />
Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen): <br />
<br />
'''Anzupassen''' ist nur der Schwellwert (600), alles andere passt automatisch (vgl. [http://www.fhemwiki.de/wiki/Notify#Hinweise]).<br />
<br />
Im Webinterface:<br />
<pre><br />
battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }<br />
</pre><br />
<br />
Alternativ im Config-File:<br />
<pre><br />
attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>battery {...}</code> - Name des userreadings mit Spezifikation, vgl. [http://fhem.de/commandref_DE.html#userReadings]<br />
: <code>return "ok" if ( ... );; return "low"</code> - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"<br />
: <code>time_str2num(ReadingsTimestamp($NAME,"state","0")</code> - Aktueller Timestamp in Sekunden, vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>time_str2num(OldTimestamp($NAME))</code> - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>600</code> - Schwellwert für "low" (600 sec = 10 min)<br />
<br />
<br />
=== Per Skript ===<br />
<br />
Andere Komponenten, wie z. B. [[:Kategorie:FS20 Components|FS20 Komponenten]], übermitteln keinen Batteriestatus. <br />
<br />
Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in [[99_myUtils_anlegen|99_myUtils.pm]]:<br />
<br />
<pre>sub check_if_alive($$) {<br />
# Expects:<br />
# 1. Devicename to be checked<br />
# 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.<br />
# Returns:<br />
# 0 -> Device dead<br />
# 1 -> Device alive<br />
# 2 -> Error<br />
my ($Device,$hours_threshold) = @_;<br />
my ($Device) = @_;<br />
my $now = time;<br />
my $Timestamp = ReadingsTimestamp($Device,"state","0");<br />
if ($Timestamp eq "0") {<br />
return 2;<br />
}<br />
<br />
my @splitdatetime = split(/ /,$Timestamp);<br />
my @splitdate = split(/-/, $splitdatetime[0]);<br />
my @splittime = split(/:/, $splitdatetime[1]);<br />
my $last_state_time = timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);<br />
my $age_in_hours = ($now - $last_state_time) / 3600;<br />
<br />
if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
return 0;<br />
} else {<br />
return 1;<br />
}<br />
<br />
}</pre><br />
<br />
Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:<br />
<br />
<pre>*05:55:55 { <br />
check_if_alive("KS300", 12);<br />
}</pre><br />
<br />
KS300 ist dabei der Name des Devices in fhem. <br />
<br />
Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.<br />
<br />
Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.<br />
<br />
=== Visualisierung ===<br />
<br />
Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.<br />
<br />
Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:<br />
<br />
<pre>Internals: <br />
NAME dum_KS300_dead <br />
NR 795 <br />
STATE nein <br />
TYPE dummy <br />
Readings: <br />
2015-04-28 07:47:48 state nein <br />
Attributes: <br />
devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green</pre><br />
<br />
Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie. <br />
<br />
Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:<br />
<br />
<pre> if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
fhem("set dum_".$Device."_dead ja");<br />
return 0;<br />
} else {<br />
fhem("set dum_".$Device."_dead nein");<br />
return 1;<br />
}</pre><br />
<br />
Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.<br />
<br />
== Links ==<br />
<br />
Siehe auch [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|visuelle Batterieüberwachung mit readingsGroup]].<br />
<br />
[[Kategorie:HOWTOS]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Batterie%C3%BCberwachung&diff=16474Batterieüberwachung2016-10-03T13:11:34Z<p>Fabian: /* Geräte ohne Batteriestatus */ Batteriestatus via userReading eingefügt</p>
<hr />
<div>== Geräte mit Batteriestatus ==<br />
<br />
[[:Kategorie:HomeMatic Components|Homematic-Komponenten]] und teilweise andere Komponenten (RFXtrx, ZWave,..) übermitteln unter anderem den Zustand der eingelegten Batterie. Um Ausfälle frühzeitig zu erkennen, kann man sich per E-Mail benachrichtigen lassen, sobald eine Batteriemeldung mit etwas anderem als "ok" gesendet wird (z.B. "low"). Zusätzlich erzeugt der unten stehende Code einen Eintrag im Logfile.<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery.* { if ($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME : Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
'''Achtung:''' Für Nutzer eines [[HM-CC-RT-DN_Funk-Heizk%C3%B6rperthermostat|HM-CC-RT-DN]] muss der Code anders aussehen, da mit diesem Thermostat erstmalig der aktuelle Spannungswert der Batterie gesendet wird, also z.B.:<br />
<br />
UG.Treppe.Heizung batteryLevel: 3.1 V<br />
<br />
Man würde bei der Verwendung des o.g. Codes bei jeder Batteriemeldung eines HM-CC-RT-DN eine E-Mail erhalten. Daher muss der o.g. Code wie folgt geändert werden (Doppelpunkt hinter "[Bb]attery"):<br />
<br />
<nowiki>define n_batt_chk notify .*:[Bb]attery:.* { if($EVENT !~ m/ok/) { \<br />
{ FB_mail('recipient@internet.de', 'FHEM Batteriewarnung', $NAME.': '.$EVENT)};; \<br />
Log 3, "$NAME: Batteriewarnung $EVENT";; \<br />
} \<br />
}</nowiki><br />
<br />
Achtung: FB_mail setzt die Installation auf einer FritzBox voraus. Für andere Hardware-/OS-Plattformen ist die Vorgehensweise unter dem Titel [[E-Mail_senden]] beschrieben.<br />
<br />
Testen kann man dies z.B. mit <code>trigger HeizungWZ Battery:low</code><br />
<br />
Man sollte auch darauf achten, dass sich das Ereignis, auf das man triggert, nicht zu häufig wiederholt (z.B. durch das Attribut <code>event-on-change-reading</code>).<br />
<br />
== Geräte ohne Batteriestatus ==<br />
<br />
=== Erweiterung des Geräts um battery-Reading ===<br />
<br />
Mit Hilfe von [http://fhem.de/commandref_DE.html#userReadings userReadings] kann man recht einfach einen Batteriestatus schätzen und als Reading bereitstellen. Dann greift auch direkt die oben beschriebene Auswertung.<br />
<br />
Die Idee ist, den zeitlichen Abstand des aktuellen Timestamps mit dem letzten geloggten Timestamp zu vergleichen und daraus auf den Batteriestatus zu schliessen - bspw. Abstand > 10min = Batterie low.<br />
<br />
Dazu muss lediglich folgendes userReading für jedes batteriebetriebene Device (ohne Batteriestatus) angelegt werden (um bei >10min "low" zu setzen): <br />
<br />
'''Anzupassen''' ist nur der Schwellwert (600), alles andere passt automatisch (vgl. [http://www.fhemwiki.de/wiki/Notify#Hinweise]).<br />
<br />
Im Webinterface:<br />
<pre><br />
battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );; return "low" }<br />
</pre><br />
<br />
Alternativ im Config-File:<br />
<pre><br />
attr MeinSensor userReadings battery { return "ok" if ( (time_str2num(ReadingsTimestamp($NAME,"state","0")) - time_str2num(OldTimestamp($NAME))) > 600 );;;; return "low" }<br />
</pre><br />
<br />
; Erläuterung:<br />
: <code>battery {...}</code> - Name des userreadings mit Spezifikation, vgl. [http://fhem.de/commandref_DE.html#userReadings]<br />
: <code>return "ok" if ( ... );; return "low"</code> - Spezifikation: Reading = "ok", wenn if erfüllt, sonst "low"<br />
: <code>time_str2num(ReadingsTimestamp($NAME,"state","0")</code> - Aktueller Timestamp in Sekunden, vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>time_str2num(OldTimestamp($NAME))</code> - Letzter Timestamp im Log in Sekunden (egal ob FileLog oder DbLog), vgl. [http://fhem.de/commandref_DE.html#perl], [http://www.fhemwiki.de/wiki/Notify#Hinweise]<br />
: <code>600</code> - Schwellwert für "low" (600 sec = 10 min)<br />
<br />
<br />
=== Per Skript ===<br />
<br />
Andere Komponenten, wie z. B. [[:Kategorie:FS20 Components|FS20 Komponenten]], übermitteln keinen Batteriestatus. <br />
<br />
Um dort dennoch einen Test darauf zu machen, ob die Batterie evtl. leer ist, kann man z. B. prüfen, wann der letzte Status des jeweiligen Gerätes empfangen wurde, etwa mit folgender Funktion in [[99_myUtils_anlegen|99_myUtils.pm]]:<br />
<br />
<pre>sub check_if_alive($$) {<br />
# Expects:<br />
# 1. Devicename to be checked<br />
# 2. Age in hours, after the expiry of which with no new state the device will be considered as dead.<br />
# Returns:<br />
# 0 -> Device dead<br />
# 1 -> Device alive<br />
# 2 -> Error<br />
my ($Device,$hours_threshold) = @_;<br />
my ($Device) = @_;<br />
my $now = time;<br />
my $Timestamp = ReadingsTimestamp($Device,"state","0");<br />
if ($Timestamp eq "0") {<br />
return 2;<br />
}<br />
<br />
my @splitdatetime = split(/ /,$Timestamp);<br />
my @splitdate = split(/-/, $splitdatetime[0]);<br />
my @splittime = split(/:/, $splitdatetime[1]);<br />
my $last_state_time = timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);<br />
my $age_in_hours = ($now - $last_state_time) / 3600;<br />
<br />
if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
return 0;<br />
} else {<br />
return 1;<br />
}<br />
<br />
}</pre><br />
<br />
Diese Funktion kann man z.B. in einem at je zu prüfendem Gerät regelmäßig (z. B. einmal am Tag um 05:55 Uhr) aufrufen, und testen, ob die letzten 12 Stunden etwas empfangen wurde:<br />
<br />
<pre>*05:55:55 { <br />
check_if_alive("KS300", 12);<br />
}</pre><br />
<br />
KS300 ist dabei der Name des Devices in fhem. <br />
<br />
Wenn das Gerät nicht geantwortet hat, erzeugt die oben vorgeschlagene Funktion einen Logeintrag.<br />
<br />
Hinweis: Dieser Batterietest schlägt natürlich auch an, wenn die FS20 Geräte noch funktionieren, aber der CUL zum Empfangen der Signale nicht mehr funktioniert. In dem Fall sind dann auf einen Schlag angeblich alle Batterien leer. Um dies zumindest teilweise abzufangen, könnte man vor dem Erzeugen des Logeintrags noch auf den state des CUL testen, dass dieser nicht "disconnected" ist.<br />
<br />
=== Visualisierung ===<br />
<br />
Der Abschnitt Links unten enthält einen Verweis, wie man den Batteriestatus visuell anzeigen kann. Das funktioniert mit der oben vorgeschlagenen Funktion mit einigen Ergänzungen auch, wenn das Gerät selbst keinen Batteriestatus anzeigt.<br />
<br />
Dafür braucht man einen zusätzlichen Dummy je zu überwachendem Gerät, mit dem Namen dum_<zu_überwachendes_Gerät>_dead. Für das Gerät KS300 heißt dieser dummy also z. B. dum_KS300_dead:<br />
<br />
<pre>Internals: <br />
NAME dum_KS300_dead <br />
NR 795 <br />
STATE nein <br />
TYPE dummy <br />
Readings: <br />
2015-04-28 07:47:48 state nein <br />
Attributes: <br />
devStateIcon ja:measure_battery_50@red nein:measure_battery_100@green</pre><br />
<br />
Dieser dummy soll hier die Zustände "ja" und "nein" annehmen können. Bei ja ist ihm über devStateIcon ein rotes Icon einer eher leeren Batterie zugewiesen, bei nein ein grünes Icon einer vollen Batterie. <br />
<br />
Nun muss noch die oben vorgeschlagene Funktion angepasst werden, um den Zustand des dummy entsprechend dem ermittelten Batteriestatus neu zu setzen. Dafür wird die Abfrage des Alters am Ende der Funktion um eine Zeile erweitert, die den Status des dummy setzt:<br />
<br />
<pre> if ($age_in_hours > $hours_threshold) {<br />
Log 1, ("check_if_alive: $Device dead, last state was $age_in_hours hours ago");<br />
fhem("set dum_".$Device."_dead ja");<br />
return 0;<br />
} else {<br />
fhem("set dum_".$Device."_dead nein");<br />
return 1;<br />
}</pre><br />
<br />
Den Dummy mit diesem devStateIcon kann man so der unter "Links" unten vorgeschlagenen readingsGroup hinzufügen, und damit auch Geräte ohne eigenen Batteriestatus überwachen.<br />
<br />
== Links ==<br />
<br />
Siehe auch [[ReadingsGroup#Auswahl_.C3.BCber_Reading-Namen.2C_Status_als_Symbol_dargestellt|visuelle Batterieüberwachung mit readingsGroup]].<br />
<br />
[[Kategorie:HOWTOS]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15592Allergy2016-06-17T16:54:35Z<p>Fabian: /* Werte aktualisieren */ Umbenannt in "Werte manuell aktualisieren"</p>
<hr />
<div>{{SEITENTITEL:allergy}}{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModForumArea=Unterstuetzende Dienste<br />
|ModCmdRef=allergy<br />
|ModTechName=60_allergy.pm<br />
|ModOwner={{Link2FU|291|Markus M.}}}}<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3 Stunden, die Tageswerte und generierten Readings lassen sich über ''ignoreList'' einschränken.<br />
Mit ''updateIgnored'' lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz></code><br />
'''<plz>''' - Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte manuell aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3 Stunden.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
[[Datei:RgPollenvorhersage.png|mini|240px|Beispielausgabe mit readingsGroup]]<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
Sollten keine farbigen Kreise dargestellt werden, sondern nur Einträge wie "rc_dot@yellow", dann müssen noch die Icon-Pfade in fhem aktualisiert werden (vgl. [[Icons#Mehr_Icons_zur_Auswahl]]).<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
Definitionen für eine [[readingsGroup]] zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in die Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in die Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema siehe [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15591Allergy2016-06-17T16:53:05Z<p>Fabian: /* Anwendungsbeispiel(e) */ Typos</p>
<hr />
<div>{{SEITENTITEL:allergy}}{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModForumArea=Unterstuetzende Dienste<br />
|ModCmdRef=allergy<br />
|ModTechName=60_allergy.pm<br />
|ModOwner={{Link2FU|291|Markus M.}}}}<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3 Stunden, die Tageswerte und generierten Readings lassen sich über ''ignoreList'' einschränken.<br />
Mit ''updateIgnored'' lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz></code><br />
'''<plz>''' - Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3 Stunden.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
[[Datei:RgPollenvorhersage.png|mini|240px|Beispielausgabe mit readingsGroup]]<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
Sollten keine farbigen Kreise dargestellt werden, sondern nur Einträge wie "rc_dot@yellow", dann müssen noch die Icon-Pfade in fhem aktualisiert werden (vgl. [[Icons#Mehr_Icons_zur_Auswahl]]).<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
Definitionen für eine [[readingsGroup]] zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in die Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in die Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema siehe [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=15575ReadingsGroup2016-06-14T07:25:35Z<p>Fabian: /* Readings löschen */ Kap. "Ausrichtung..." eingefügt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das Fhem-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre>set d_label Heizung Heizung <br />
set d_label Temperatur Temperatur <br />
set d_label Status Status <br />
set d_label Wochenplan Wochenplan <br />
set d_label Werktag Werktag <br />
set d_label Samstag Samstag <br />
set d_label Sonntag Sonntag <br />
set d_label Zeitraum1 Zeitraum 1 <br />
set d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]].<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat>\<br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das Fhem Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FhemWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer_Wasser valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
=== Ausrichtung der Tabelle drehen (horizontal/vertikal) ===<br />
Eine Readingsgroup wird standardmäßig immer zeilenweise aufgebaut, zB. jedes Gerät in eine neue Zeile. Die Werte der Geräte werden dann in den Spalten dargestellt. <br />
Wenn man eine Readingsgroup für nur ein Gerät mit vielen Readings hat (zB. [[Allergy]]), so kann man die Darstellung horizontal oder vertikal ausrichten, indem man die Readingsgroup detailliert definiert. Ein Bsp. dazu liefert der Foreneintrag [https://forum.fhem.de/index.php/topic,37194.msg440446.html#msg440446] :<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy <PLZ><br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
<br />
# Pollen in Spalten, Tage in Zeilen<br />
define PollenAlarmHorizontal readingsGroup <>,<Ampfer>,<Ambrosia>,<Beifuß>,<Birke>,<Buche>,<Eiche>,<Erle>,<Gräser>,<Hasel>,<Pappel>,<Roggen>,<Ulme>,<Wegerich>,<Weide> \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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 \<br />
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<br />
attr PollenAlarm nonames 1<br />
attr PollenAlarm valueFormat %VALUE<br />
attr PollenAlarm valueIcon %VALUE<br />
<br />
# Tage in Spalten, Pollen in Zeilen<br />
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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia\<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer\<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss\<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke\<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche\<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche\<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle\<br />
Pollenflugvorhersage:<Gräser>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser\<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel\<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen\<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme\<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich\<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
</pre><br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Icons&diff=15358Icons2016-05-16T13:45:59Z<p>Fabian: /* Weitere Tipps */ Kap. "Icons Farben zuweisen" erstellt</p>
<hr />
<div>Icons - alles rund um die Icons in Fhem<br />
= Fhem mit Icons verschönern =<br />
== Geräten Icons zuweisen ==<br />
Im FHEMWEB auf Detail-Ansicht des Gerätes gehen, danach in der attr Zeile per dropdown<br />
# Icon auswählen, um das Icon zu wählen, das standardmäßig links vom Gerät gezeigt wird; alternativ ganz unten auf '''Select Icon''' klicken, dann bekommt ihr alle Bilder angezeigt<br />
# '''devStateIcon auswählen''', um unterschiedliche Schaltzustände mit unterschiedlichen Icons zu versehen; alternativ ganz unten auf '''Extend devStateIcon''' klicken, dann bekommt ihr alle Bilder angezeigt und könnt sie dem jeweiligen Schaltzustand zuordnen.<br />
<br />
Dabei gilt folgendes:<br />
* Icon-Dateiname OHNE Dateiendung eingeben<br />
* wenn es sich bei dem Icon um eine svg-Datei handelt, kann mit @farbe die Farbe beeinflusst werden, z.B. <br /> <code>attr Geraet devStateIcon an:general_an@green aus:general_aus@red</code>, <br /> wobei hier die beiden Dateien general_an.svg und general_aus.svg heißen.<br />
* statt des Standardfarbnamens, kann übrigens auch der 6-stellige Hex-Code übergeben werden (ohne # am Anfang). Den Code könnt ihr z.B. hier bei [http://www.colorpicker.com Colorpicker] generieren<br />
* Möchte man dass bei Klick auf das Icon auch eine Aktion ausgelöst wird, kann man dies als dritten Parameter mit angeben. Beispiel für einen Wechsel zwischen "arround" und "away": <code>arround:status_available:away away:status_away_2:arround</code>.<br />
<br />
Wenn ihr die Änderungen wie oben beschrieben durchführt, könnt ihr das Ergebnis gleich betrachten. Wenn alles passt, dann noch '''Save config''' drücken, dann wird alles fest abgespeichert.<br />
<br />
== Größe der Icons verändern ==<br />
Auch das kein Problem. Öffnet einfach die für Eurer Template (wie sieht fhem bei Euch aus: rechts unten -> Select Style -> das was ihr dort gewählt habt ist Euer Template) zuständige css-Datei. Diese findet ihr im fhem-Verzeichnis unter www/pgm2. Dort fügt ihr einfach folgende Zeile ein und ändert ggf. die Größenangaben.<br />
<pre>svg { height:32px; width:32px; }</pre><br />
<br />
== Mehr Icons zur Auswahl ==<br />
Grundsätzlich sind bei aktuellen fhem-Installationen die meisten Icons standardmäßig aktiviert. Navigiert doch einfach mal im fhem Verzeichnis in den www Ordner und dort in images. Die Ordner default, openautomation und fhemSVG sind standardmäßig aktiviert, d.h., Icons aus diesen Ordnern werden in fhem angezeigt. Wenn ihr zusätzlich die Icons auch aus den anderen Ordnern (z.B. icons_small) verwenden wollt, dann ergänzt einfach die entsprechende Zeile "WEB iconPath" in der fhem.cfg:<br />
<pre>attr WEB iconPath fhemSVG:openautomation:default:icons_small</pre><br />
<br />
Das gleiche gilt, wenn ihr eine ältere fhem-Installation habt und noch nicht die Bilder z.B. aus fhemSVG angezeigt bekommt.<br />
<br />
== Icons Farben zuweisen ==<br />
Man kann Icons beliebige Farben zuweisen, indem man den Icon-Name per "@" mit einem Farbnamen oder einer Farbcodierung versieht.<br />
<pre><br />
rc_dot@red<br />
rc_dot@#a1d490<br />
</pre><br />
Farben kann man bspw. auf den folgenden Seiten finden:<br />
* [http://www.colorpicker.com www.colorpicker.com]<br />
* [http://www.html-color-names.com www.html-color-names.com]<br />
<br />
== Weitere Tipps ==<br />
Weitere Tipps zu Icons finden sich auch auf der Seite [[Slider für HM-Rolladensteuerung anzeigen]].<br />
<br />
= Eigene Icons erstellen =<br />
Falls ihr eigene Icons basteln wollt - sehr gerne. Umso besser, wenn ihr diese dann mit uns teilt. Der passende [http://forum.fhem.de/index.php/topic,12605.0.html Thread im Forum].<br />
<br />
== SVG-Icons ==<br />
Hier einige Tipps zum Erstellen von SVG-Icons. SVGs bieten einige Vorteile:<br />
* SVGs sind vektorbasiert und somit frei skalierbar<br />
* SVGs sind, wenn man sie genauer betrachtet, gut lesbarer und veränderbarer Quellcode und können deswegen leicht über css manipuliert werden<br />
<br />
Wie geht es nun:<br />
* [http://inkscape.org/download/?lang=de Inkscape] besorgen (Open Source)<br />
* Loszeichnen<br />
<br />
Jetzt wird es wichtig - fhem ist etwas sensibel, was svgs anbelangt und will diese zudem farblich umgestalten. Daher folgendes unbedingt beachten:<br />
<br />
* fhem ersetzt bei allen fill:#000000 und fill="#000000" die sechs Nullen mit einem Farbcode, wenn dieser mit übergeben wurde (sh. Fhem mit Icons verschönern weiter oben) - das solltet ihr beim zeichnen beachten<br />
* daher arbeite ich immer so, dass ich beispielsweise Rechtecke/Kreise zeichne und diese dann mit "Kontur in Pfad umwandeln" umwandle -> dann ist das Rechteck transparent, die Linie schwarz (und wird von fhem erstetzt) und alles klappt<br />
* alle Texte müssen in Pfade umgewandelt werden<br />
* das gesamte Bild muss als "Normales SVG" gespeichert werden (Standardeinstellung bei Inkscape ist "Inkscape SVG")<br />
* Wenn die Grafik nicht angezeigt wird sondern nur Text: In einem Editor den Inhalt mit einer funktionierenden SVG-Datei vergleichen und anpassen.<br />
* letzter wichtiger Tipp: Eine Zeile darf im SVG nicht fehlen, sonst zeigt fhem es nicht an. Wenn ihr Euer SVG in einem Texteditor öffnet (ich empfehle notepad++), schaut in in der <svg>-Definition, ob die Zeile mit viewBox dabei ist. Wenn nicht, dann nach unterem Format ergänzen.<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8" standalone="no"?><br />
<!-- Created with Inkscape (http://www.inkscape.org/) --><br />
<svg<br />
version="1.0"<br />
width="585"<br />
height="585"<br />
viewBox="0 0 585 585"<br />
id="svg2421"<br />
sodipodi:docname="usb-stick.svg"><br />
</pre><br />
<br />
== SVG-Icons für das Modul remotecontrol: Schriftvorlage ==<br />
Wer beispielsweise für das Modul remotecontrol noch andere Beschriftungen braucht, der kann sich diese ganz fix selbst machen. Im Ordner fhem\www\images\fhemSVG findet ihr die Datei rc_templatebutton.svg. Mit der macht ihr folgendes:<br />
Ganz einfach inkscape runterladen (http://inkscape.org/download/?lang=de), Datei öffnen, auf Text klicken, dann oben in der Leiste auf Text -> Schrift und Text -> Reiter Text, Text ändern. Ggf. Größe/Position anpassen, dann Pfad -> Objekt in Pfad umwandeln, dann Datei -> Speichern unter -> euer name und "Normales SVG" => FERTIG<br />
<br />
[[Kategorie:HOWTOS]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15357Allergy2016-05-16T13:29:05Z<p>Fabian: /* Anwendungsbeispiel(e) */ Screenshot eingefügt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModFTopic=<br />
|ModForumArea=<br />
|ModTechName=60_allergy.pm<br />
|ModOwner=Markus / <br />
}}<br />
<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3h, die Tageswerte und generierten Readings lassen sich über ignoreList einschränken.<br />
Mit updateIgnored lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz></code><br />
'''<plz>''' - Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3h.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
Sollten keine farbigen Kreise dargestellt werden, sondern nur Einträge wie "rc_dot@yellow", dann müssen noch die Icon-Pfade in fhem aktualisiert werden (vgl. [[Icons#Mehr_Icons_zur_Auswahl]]).<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<br />
[[Datei:RgPollenvorhersage.png|mini|240px]]<br />
<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
ReadingsGroup zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in den Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema s. [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Datei:RgPollenvorhersage.png&diff=15356Datei:RgPollenvorhersage.png2016-05-16T13:26:19Z<p>Fabian: </p>
<hr />
<div></div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15355Allergy2016-05-16T13:22:28Z<p>Fabian: /* Anwendungsbeispiel(e) */ Hinweis zu Icons eingefügt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModFTopic=<br />
|ModForumArea=<br />
|ModTechName=60_allergy.pm<br />
|ModOwner=Markus / <br />
}}<br />
<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3h, die Tageswerte und generierten Readings lassen sich über ignoreList einschränken.<br />
Mit updateIgnored lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz></code><br />
'''<plz>''' - Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3h.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
Sollten keine farbigen Kreise dargestellt werden, sondern nur Einträge wie "rc_dot@yellow", dann müssen noch die Icon-Pfade in fhem aktualisiert werden (vgl. [[Icons#Mehr_Icons_zur_Auswahl]]).<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
ReadingsGroup zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in den Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema s. [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15354Allergy2016-05-16T13:12:03Z<p>Fabian: Typos</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModFTopic=<br />
|ModForumArea=<br />
|ModTechName=60_allergy.pm<br />
|ModOwner=Markus / <br />
}}<br />
<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3h, die Tageswerte und generierten Readings lassen sich über ignoreList einschränken.<br />
Mit updateIgnored lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz></code><br />
'''<plz>''' - Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3h.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
ReadingsGroup zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in den Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema s. [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Allergy&diff=15353Allergy2016-05-16T13:06:45Z<p>Fabian: Initial erstellt nach Forums-Threat</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Legt ein Device an, das Vorhersagedaten zum Pollenflug der nächsten 7 Tage ausliest.<br />
|ModType=d<br />
|ModFTopic=<br />
|ModForumArea=<br />
|ModTechName=60_allergy.pm<br />
|ModOwner=Markus / <br />
}}<br />
<br />
[[allergy]] ist ein Modul zur Vorhersage des Pollenflugs ausgehend von einer deutschen Postleitzahl. Folgende Allergene werden ermittelt:<br />
Ambrosia, Ampfer, Beifuß, Birke, Buche, Eiche, Erle, Gräser, Hasel, Pappel, Roggen, Ulme, Wegerich, Weide<br />
<br />
== Voraussetzungen ==<br />
Das Perl Modul XML::Simple wird benötigt.<br />
<br />
Installation unter Ubuntu/Debian: <code>sudo apt-get install libxml-simple-perl</code><br />
<br />
== Anwendung ==<br />
Updates erfolgen automatisch alle 3h, die Tageswerte und generierten Readings lassen sich über ignoreList einschränken.<br />
Mit updateIgnored lassen sich die leeren und ignorierten Readings trotzdem generieren.<br />
<br />
=== Define ===<br />
:<code>define <Name> allergy <plz><br />
<br />
Erläuterung der Parameter im '''define''':<br />
;<plz> <br />
:Postleitzahl in Deutschland<br />
<br />
Beispiel:<br />
:<code>define Pollenflugvorhersage allergy 10115</code><br />
<br />
=== Werte aktualisieren ===<br />
:<code>get <Name> data</code><br />
Beispiel:<br />
:<code>get Pollenflugvorhersage data</code><br />
<br />
=== Aktualisierungsintervall festlegen ===<br />
Updates erfolgen automatisch alle 3h.<br />
<br />
=== Weitere Attribute ===<br />
;ignoreList<br />
:Tageswerte und generierten Readings einschränken<br />
<br />
;updateEmpty<br />
:leere Readings trotzdem generieren<br />
<br />
;updateIgnored<br />
:ignorierte Readings trotzdem generieren<br />
<br />
;levelsFormat<br />
:legt eine individuelle Formatierung der Readings fest<br />
<br />
;stateFormat<br />
:<br />
<br />
== Anwendungsbeispiel(e) ==<br />
Im folgenden Beispiel sind folgende Besonderheiten enthalten:<br />
* per levelsFormat werden die Werte als farbige Punkte formatiert<br />
* per Skripten werden die Werte für den Vortag erstellt und als fc0 eingetragen (falls nicht gewünscht, alle fc0-Einträge entfernen)<br />
<br />
'''Definition der Pollenflugvorhersage für Berlin:'''<br />
<pre><br />
define Pollenflugvorhersage allergy 10115<br />
attr Pollenflugvorhersage levelsFormat rc_dot@white,rc_dot@yellow,rc_dot@orange,rc_dot@red<br />
attr Pollenflugvorhersage room Wetter-vorhersage<br />
attr Pollenflugvorhersage stateFormat fc1_maximum<br />
attr Pollenflugvorhersage updateEmpty 1<br />
attr Pollenflugvorhersage updateIgnored 1<br />
</pre><br />
<br />
'''Darstellung der Vorhersage''' (Quelle: [https://forum.fhem.de/index.php/topic,37194.120.html]):<br />
<br />
ReadingsGroup zur Darstellung der Pollenflugvorhersage:<br />
<pre><br />
define rgPollenvorhersage 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 \<br />
Pollenflugvorhersage:<Ambrosia>,fc0_Ambrosia,fc1_Ambrosia,fc2_Ambrosia,fc3_Ambrosia,fc4_Ambrosia,fc5_Ambrosia,fc6_Ambrosia,fc7_Ambrosia \<br />
Pollenflugvorhersage:<Ampfer>,fc0_Ampfer,fc1_Ampfer,fc2_Ampfer,fc3_Ampfer,fc4_Ampfer,fc5_Ampfer,fc6_Ampfer,fc7_Ampfer \<br />
Pollenflugvorhersage:<Beifuß>,fc0_Beifuss,fc1_Beifuss,fc2_Beifuss,fc3_Beifuss,fc4_Beifuss,fc5_Beifuss,fc6_Beifuss,fc7_Beifuss \<br />
Pollenflugvorhersage:<<b>Birke<Birke</b>>,fc0_Birke,fc1_Birke,fc2_Birke,fc3_Birke,fc4_Birke,fc5_Birke,fc6_Birke,fc7_Birke \<br />
Pollenflugvorhersage:<Buche>,fc0_Buche,fc1_Buche,fc2_Buche,fc3_Buche,fc4_Buche,fc5_Buche,fc6_Buche,fc7_Buche \<br />
Pollenflugvorhersage:<Eiche>,fc0_Eiche,fc1_Eiche,fc2_Eiche,fc3_Eiche,fc4_Eiche,fc5_Eiche,fc6_Eiche,fc7_Eiche \<br />
Pollenflugvorhersage:<<b>Erle<Erle</b>>,fc0_Erle,fc1_Erle,fc2_Erle,fc3_Erle,fc4_Erle,fc5_Erle,fc6_Erle,fc7_Erle \<br />
Pollenflugvorhersage:<<b>Gräser</b>>,fc0_Graeser,fc1_Graeser,fc2_Graeser,fc3_Graeser,fc4_Graeser,fc5_Graeser,fc6_Graeser,fc7_Graeser \<br />
Pollenflugvorhersage:<<b>Hasel<Hasel</b>>,fc0_Hasel,fc1_Hasel,fc2_Hasel,fc3_Hasel,fc4_Hasel,fc5_Hasel,fc6_Hasel,fc7_Hasel \<br />
Pollenflugvorhersage:<Pappel>,fc0_Pappel,fc1_Pappel,fc2_Pappel,fc3_Pappel,fc4_Pappel,fc5_Pappel,fc6_Pappel,fc7_Pappel\<br />
Pollenflugvorhersage:<Roggen>,fc0_Roggen,fc1_Roggen,fc2_Roggen,fc3_Roggen,fc4_Roggen,fc5_Roggen,fc6_Roggen,fc7_Roggen \<br />
Pollenflugvorhersage:<Ulme>,fc0_Ulme,fc1_Ulme,fc2_Ulme,fc3_Ulme,fc4_Ulme,fc5_Ulme,fc6_Ulme,fc7_Ulme \<br />
Pollenflugvorhersage:<Wegerich>,fc0_Wegerich,fc1_Wegerich,fc2_Ulme,fc3_Wegerich,fc4_Wegerich,fc5_Wegerich,fc6_Wegerich,fc7_Wegerich \<br />
Pollenflugvorhersage:<Weide>,fc0_Weide,fc1_Weide,fc2_Weide,fc3_Weide,fc4_Weide,fc5_Weide,fc6_Weide,fc7_Weide<br />
attr rgPollenvorhersage mapping %READING<br />
attr rgPollenvorhersage room Wetter-vorhersage<br />
attr rgPollenvorhersage valueIcon %VALUE<br />
attr rgPollenvorhersage valueStyle %VALUE<br />
</pre><br />
<br />
Die Pollenvorhersage zeigt standardmäßig nicht die Werte des Vortags an. Möchte man dies trotzdem haben so helfen diese beiden Skripte:<br />
<pre><br />
# kopiert um 12:00 die Werte des aktuellen Tags fc1 in Temp-Einträge fcy<br />
define PollenAt12 at *12:00 \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ambrosia [Pollenflugvorhersage:fc1_Ambrosia];; \<br />
setreading Pollenflugvorhersage fcy_Ampfer [Pollenflugvorhersage:fc1_Ampfer];; \<br />
setreading Pollenflugvorhersage fcy_Beifuss [Pollenflugvorhersage:fc1_Beifuss];; \<br />
setreading Pollenflugvorhersage fcy_Birke [Pollenflugvorhersage:fc1_Birke];; \<br />
setreading Pollenflugvorhersage fcy_Buche [Pollenflugvorhersage:fc1_Buche];; \<br />
setreading Pollenflugvorhersage fcy_Eiche [Pollenflugvorhersage:fc1_Eiche];; \<br />
setreading Pollenflugvorhersage fcy_Erle [Pollenflugvorhersage:fc1_Erle];; \<br />
setreading Pollenflugvorhersage fcy_Esche [Pollenflugvorhersage:fc1_Esche];; \<br />
setreading Pollenflugvorhersage fcy_Graeser [Pollenflugvorhersage:fc1_Graeser];; \<br />
setreading Pollenflugvorhersage fcy_Hasel [Pollenflugvorhersage:fc1_Hasel];; \<br />
setreading Pollenflugvorhersage fcy_Pappel [Pollenflugvorhersage:fc1_Pappel];; \<br />
setreading Pollenflugvorhersage fcy_Roggen [Pollenflugvorhersage:fc1_Roggen];; \<br />
setreading Pollenflugvorhersage fcy_Ulme [Pollenflugvorhersage:fc1_Ulme];; \<br />
setreading Pollenflugvorhersage fcy_Wegerich [Pollenflugvorhersage:fc1_Wegerich];; \<br />
setreading Pollenflugvorhersage fcy_Weide [Pollenflugvorhersage:fc1_Weide];; \<br />
setreading Pollenflugvorhersage fcy_day_of_week [Pollenflugvorhersage:fc1_day_of_week]<br />
<br />
# kopiert um 24:00 die Temp-Einträge fcy in den Vortags-Einträge fc0<br />
define PollenAt24 at *00:00 \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ambrosia [Pollenflugvorhersage:fcy_Ambrosia];; \<br />
setreading Pollenflugvorhersage fc0_Ampfer [Pollenflugvorhersage:fcy_Ampfer];; \<br />
setreading Pollenflugvorhersage fc0_Beifuss [Pollenflugvorhersage:fcy_Beifuss];; \<br />
setreading Pollenflugvorhersage fc0_Birke [Pollenflugvorhersage:fcy_Birke];; \<br />
setreading Pollenflugvorhersage fc0_Buche [Pollenflugvorhersage:fcy_Buche];; \<br />
setreading Pollenflugvorhersage fc0_Eiche [Pollenflugvorhersage:fcy_Eiche];; \<br />
setreading Pollenflugvorhersage fc0_Erle [Pollenflugvorhersage:fcy_Erle];; \<br />
setreading Pollenflugvorhersage fc0_Esche [Pollenflugvorhersage:fcy_Esche];; \<br />
setreading Pollenflugvorhersage fc0_Graeser [Pollenflugvorhersage:fcy_Graeser];; \<br />
setreading Pollenflugvorhersage fc0_Hasel [Pollenflugvorhersage:fcy_Hasel];; \<br />
setreading Pollenflugvorhersage fc0_Pappel [Pollenflugvorhersage:fcy_Pappel];; \<br />
setreading Pollenflugvorhersage fc0_Roggen [Pollenflugvorhersage:fcy_Roggen];; \<br />
setreading Pollenflugvorhersage fc0_Ulme [Pollenflugvorhersage:fcy_Ulme];; \<br />
setreading Pollenflugvorhersage fc0_Wegerich [Pollenflugvorhersage:fcy_Wegerich];; \<br />
setreading Pollenflugvorhersage fc0_Weide [Pollenflugvorhersage:fcy_Weide];; \<br />
setreading Pollenflugvorhersage fc0_day_of_week [Pollenflugvorhersage:fcy_day_of_week]<br />
</pre><br />
<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=37194|LinkText=Forum-Thread zum Modul}}<br />
* Andere Möglichkeiten zum Thema s. [[Pollenflug]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Pollenflug&diff=15352Pollenflug2016-05-16T12:16:44Z<p>Fabian: Kap. "Modul Allergy" eingefügt</p>
<hr />
<div>Genauso wie [[Wetter und Wettervorhersagen|Wettervorhersagen]], gibt es Pollenflug-Vorhersagen von verschiedensten Anbietern. Verschiedene Einbindungs- und Darstellungsmöglichkeiten sollen hier beschrieben werden.<br />
<br />
== Donnerwetter per HTTPMOD ==<br />
Die Daten können mit [[HTTPMOD]] aus der Donnerwetterseite ausgelesen werden. Als Voraussetzung benötigt man die konkrete URL. Dazu geht man einfach auf die [http://www.donnerwetter.de www.donnerwetter.de], sucht seine Stadt und wählt Pollenflug aus. Die URL dieser Seite wird nun ausgelesen.<br />
<br />
'''Anfänger-Tip:''' Das hier aufgeführte Bsp. kann mit nur einer einzigen Anpassung übernommen werden - und wenn Du in Berlin wohnst, brauchst Du garnichts anzupassen... ;-).<br />
<br />
=== Daten auslesen ===<br />
Der folgende Code liest sämtliche von Donnerwetter bereitgestellten Pollen-Informationen für Berlin aus. Wenn man nicht alle benötigt, kann man einfach die entsprechenden readingXXName und readingXXRegex weglassen. Der Abruf erfolgt täglich (alle 86400 Sekunden).<br />
<br />
'''Wichtig''' ist der Eintrag "attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)", ohne den HTTPMOD nur eine Fehlermeldung wirft.<br />
<br />
<pre><br />
define Pollenflug HTTPMOD http://www.donnerwetter.de/pollenflug/berlin/DE14356.html 86400<br />
attr Pollenflug userattr enableControlSet reading01Name reading01Regex reading02Name reading02Regex reading03Name reading03Regex reading04Name reading04Regex reading05Name reading05Regex reading06Name reading06Regex reading07Name reading07Regex reading08Name reading08Regex reading09Name reading09Regex reading10Name reading10Regex reading11Name reading11Regex reading12Name reading12Regex reading13Name reading13Regex reading14Name reading14Regex reading15Name reading15Regex reading16Name reading16Regex reading17Name reading17Regex reading18Name reading18Regex reading19Name reading19Regex reading20Name reading20Regex reading21Name reading21Regex reading22Name reading22Regex reading23Name reading23Regex reading24Name reading24Regex reading25Name reading25Regex reading26Name reading26Regex reading27Name reading27Regex reading28Name reading28Regex reading29Name reading29Regex reading30Name reading30Regex reading31Name reading31Regex reading32Name reading32Regex reading33Name reading33Regex requestHeader1<br />
attr Pollenflug group Pollenflug (Donnerwetter)<br />
attr Pollenflug reading01Name Erle<br />
attr Pollenflug reading01Regex (?s)Erle.*?poll([\d])<br />
attr Pollenflug reading02Name Hasel<br />
attr Pollenflug reading02Regex (?s)Hasel.*?poll([\d])<br />
attr Pollenflug reading03Name Löwenzahn<br />
attr Pollenflug reading03Regex (?s)L.wenzahn.*?poll([\d])<br />
attr Pollenflug reading04Name Gräser<br />
attr Pollenflug reading04Regex (?s)Gr.ser.*?poll([\d])<br />
attr Pollenflug reading05Name Gerste<br />
attr Pollenflug reading05Regex (?s)Gerste.*?poll([\d])<br />
attr Pollenflug reading06Name Linde<br />
attr Pollenflug reading06Regex (?s)Linde.*?poll([\d])<br />
attr Pollenflug reading07Name Beifuss<br />
attr Pollenflug reading07Regex (?s)Beifu.*?poll([\d])<br />
attr Pollenflug reading08Name Gansefuss<br />
attr Pollenflug reading08Regex (?s)Gansefu.*?poll([\d])<br />
attr Pollenflug reading09Name Mais<br />
attr Pollenflug reading09Regex (?s)Mais.*?poll([\d])<br />
attr Pollenflug reading10Name Brennessel<br />
attr Pollenflug reading10Regex (?s)Brennessel.*?poll([\d])<br />
attr Pollenflug reading11Name Hafer<br />
attr Pollenflug reading11Regex (?s)Hafer.*?poll([\d])<br />
attr Pollenflug reading12Name Roggen<br />
attr Pollenflug reading12Regex (?s)Roggen.*?poll([\d])<br />
attr Pollenflug reading13Name Weizen<br />
attr Pollenflug reading13Regex (?s)Weizen.*?poll([\d])<br />
attr Pollenflug reading14Name Spitzwegerich<br />
attr Pollenflug reading14Regex (?s)Spitzwegerich.*?poll([\d])<br />
attr Pollenflug reading15Name Raps<br />
attr Pollenflug reading15Regex (?s)Raps.*?poll([\d])<br />
attr Pollenflug reading16Name Hopfen<br />
attr Pollenflug reading16Regex (?s)Hopfen.*?poll([\d])<br />
attr Pollenflug reading17Name Holunder<br />
attr Pollenflug reading17Regex (?s)Holunder.*?poll([\d])<br />
attr Pollenflug reading18Name Ulme<br />
attr Pollenflug reading18Regex (?s)Ulme.*?poll([\d])<br />
attr Pollenflug reading19Name Pappel<br />
attr Pollenflug reading19Regex (?s)Pappel.*?poll([\d])<br />
attr Pollenflug reading20Name Weide<br />
attr Pollenflug reading20Regex (?s)Weide.*?poll([\d])<br />
attr Pollenflug reading21Name Birke<br />
attr Pollenflug reading21Regex (?s)Birke.*?poll([\d])<br />
attr Pollenflug reading22Name Eiche<br />
attr Pollenflug reading22Regex (?s)Eiche.*?poll([\d])<br />
attr Pollenflug reading23Name Esche<br />
attr Pollenflug reading23Regex (?s)Esche.*?poll([\d])<br />
attr Pollenflug reading24Name Platane<br />
attr Pollenflug reading24Regex (?s)Platane.*?poll([\d])<br />
attr Pollenflug reading25Name Flieder<br />
attr Pollenflug reading25Regex (?s)Flieder.*?poll([\d])<br />
attr Pollenflug reading26Name Ambrosia<br />
attr Pollenflug reading26Regex (?s)Ambrosia.*?poll([\d])<br />
attr Pollenflug reading27Name Buche<br />
attr Pollenflug reading27Regex (?s)Buche.*?poll([\d])<br />
attr Pollenflug reading28Name Rotbuche<br />
attr Pollenflug reading28Regex (?s)Rotbuche.*?poll([\d])<br />
attr Pollenflug reading29Name Ahorn<br />
attr Pollenflug reading29Regex (?s)Ahorn.*?poll([\d])<br />
attr Pollenflug reading30Name Nessel<br />
attr Pollenflug reading30Regex (?s)Nessel.*?poll([\d])<br />
attr Pollenflug reading31Name Kiefer<br />
attr Pollenflug reading31Regex (?s)Kiefer.*?poll([\d])<br />
attr Pollenflug reading32Name Tanne<br />
attr Pollenflug reading32Regex (?s)Tanne.*?poll([\d])<br />
attr Pollenflug reading33Name Fichte<br />
attr Pollenflug reading33Regex (?s)Fichte.*?poll([\d])<br />
attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)<br />
attr Pollenflug room Wetter-vorhersage<br />
</pre><br />
<br />
'''Erläuterung der Regex:'''<br />
<br />
HTTPMOD ruft einen riesigen Textblock ab. Darin sieht der relevante Abschnitt für "Hasel" wie folgt aus:<br />
<br />
<pre> Hasel</font></b></font></td> <td><img src="http://static.donnerwetter.de/images/poll0.gif" </pre><br />
<br />
Der reguläre Ausdruck dazu <br />
* sucht mit evtl. vorangegangenem Leerzeichen <code>(?s)</code><br />
* den Begriff <code>Hasel</code>,<br />
* lässt alles bis zum <code>poll</code> von poll0.gif aus und<br />
* liest die nachfolgende Dezimalzahl aus <code>([\d])</code> (bei poll0.gif also eine Null).<br />
<br />
<pre> (?s)Hasel.*?poll([\d]) </pre><br />
<br />
=== Daten darstellen ===<br />
[[Datei:pollenflug_balken.png|mini|200px]]<br />
Man kann die ausgelesenen Daten auf verschiedenste Weisen darstellen (vgl. auch die Links unten). Im folgenden ist eine einfache tabellarische Darstellung mit Hilfe einer [[ReadingsGroup]] beschrieben. Als kleines Schmankerl werden die Werte als Balken dargestellt (vgl. auch [[ReadingsGroup#Einfache_Balkendiagramme]]) und nur die Werte >0 dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]). <br />
<br />
<pre><br />
define rgPollenflug readingsGroup Pollenflug<br />
attr rgPollenflug mapping %READING<br />
attr rgPollenflug nolinks 1<br />
attr rgPollenflug notime 1<br />
attr rgPollenflug room Wetter-vorhersage<br />
attr rgPollenflug valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }<br />
attr rgPollenflug valueStyle { BalkenPollen($VALUE) }<br />
</pre><br />
<br />
Kurze Erläuterung:<br />
* <code>mapping %READING</code> Es wird der readingXXName in der Tabelle angezeigt.<br />
* <code>valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code> Werte = 0 (also kein Pollenflug) werden nicht dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]).<br />
* <code>valueStyle { BalkenPollen($VALUE) }</code> Der Balken wird über die Funktion "BalkenPollen" erzeugt (s.u.).<br />
<br />
Die notwendige Funktion für die [[99_myUtils_anlegen|99_myUtils.pm]] sieht wie folgt aus:<br />
<br />
<source lang="perl"><br />
# Balkenanzeige für Pollenflug<br />
sub BalkenPollen($) <br />
{<br />
my ($pollen) = @_;<br />
<br />
my $maxValue = 3;<br />
<br />
my $percent = $pollen / $maxValue * 100;<br />
<br />
my $color = "red";<br />
if ($pollen < 2) { $color = "yellow"; } <br />
elsif ($pollen < 3) { $color = "orange"; }<br />
<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Kurze Erläuterung (weitere Infos s. [[ReadingsGroup#Einfache_Balkendiagramme]]):<br />
* <code>$maxValue = 3</code> Donnerwetter liefert als Maximalwert 3 zurück.<br />
* <code>$color</code> Der Balken ist rot bei 3, orange bei 2, gelb bei 1.<br />
* <code>width: 200px;</code> Der Balken ist 200px breit.<br />
<br />
<br />
== Modul Allergy ==<br />
Es gibt ein eigenes Modul [[Allergy]], das komfortabel Daten zur Pollenvorhersage zusammenträgt. Somit braucht man nicht per HTTPMOD selbst diese Daten auszulesen.<br />
<br />
<br />
== Pollenkalender einbinden ==<br />
Einen statischen Pollenkalender als Grafik kann man bspw. wie folgt einbinden:<br />
define Pollenflug_Grafik_WD weblink image http://www.wetterdienst.de/imgs/pollenflugkalendar.jpg<br />
attr Pollenflug_Grafik_WD group Pollenflug (Wetterdienst)<br />
attr Pollenflug_Grafik_WD htmlattr width="50%" height="50%" frameborder="0" marginheight="0" marginwidth="0"<br />
attr Pollenflug_Grafik_WD room Wetter-vorhersage<br />
<br />
<br />
== Links ==<br />
* Foren-Diskussionen: [https://forum.fhem.de/index.php?topic=47769.0]<br />
* Bsp. auf Jürgens Technikwelt [http://www.juergenstechnikwelt.de/smarthome-2/smarthome-mit-fhem-pollenflug-aus-webseite-auslesen-und-im-tablet-ui-anzeigen/]<br />
* [[Wetter und Wettervorhersagen]]<br />
* Allergy-Modul im [https://forum.fhem.de/index.php?topic=37194.0 Forum]<br />
<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Wetterstationen]] <!-- eigentlich eine "Hardware-Kategorie", passt aber trotzdem --></div>Fabianhttp://wiki.fhem.de/w/index.php?title=Pollenflug&diff=15351Pollenflug2016-05-16T12:13:18Z<p>Fabian: /* Donnerwetter */ Kap. Titel ergänzt</p>
<hr />
<div>Genauso wie [[Wetter und Wettervorhersagen|Wettervorhersagen]], gibt es Pollenflug-Vorhersagen von verschiedensten Anbietern. Verschiedene Einbindungs- und Darstellungsmöglichkeiten sollen hier beschrieben werden.<br />
<br />
== Donnerwetter per HTTPMOD ==<br />
Die Daten können mit [[HTTPMOD]] aus der Donnerwetterseite ausgelesen werden. Als Voraussetzung benötigt man die konkrete URL. Dazu geht man einfach auf die [http://www.donnerwetter.de www.donnerwetter.de], sucht seine Stadt und wählt Pollenflug aus. Die URL dieser Seite wird nun ausgelesen.<br />
<br />
'''Anfänger-Tip:''' Das hier aufgeführte Bsp. kann mit nur einer einzigen Anpassung übernommen werden - und wenn Du in Berlin wohnst, brauchst Du garnichts anzupassen... ;-).<br />
<br />
=== Daten auslesen ===<br />
Der folgende Code liest sämtliche von Donnerwetter bereitgestellten Pollen-Informationen für Berlin aus. Wenn man nicht alle benötigt, kann man einfach die entsprechenden readingXXName und readingXXRegex weglassen. Der Abruf erfolgt täglich (alle 86400 Sekunden).<br />
<br />
'''Wichtig''' ist der Eintrag "attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)", ohne den HTTPMOD nur eine Fehlermeldung wirft.<br />
<br />
<pre><br />
define Pollenflug HTTPMOD http://www.donnerwetter.de/pollenflug/berlin/DE14356.html 86400<br />
attr Pollenflug userattr enableControlSet reading01Name reading01Regex reading02Name reading02Regex reading03Name reading03Regex reading04Name reading04Regex reading05Name reading05Regex reading06Name reading06Regex reading07Name reading07Regex reading08Name reading08Regex reading09Name reading09Regex reading10Name reading10Regex reading11Name reading11Regex reading12Name reading12Regex reading13Name reading13Regex reading14Name reading14Regex reading15Name reading15Regex reading16Name reading16Regex reading17Name reading17Regex reading18Name reading18Regex reading19Name reading19Regex reading20Name reading20Regex reading21Name reading21Regex reading22Name reading22Regex reading23Name reading23Regex reading24Name reading24Regex reading25Name reading25Regex reading26Name reading26Regex reading27Name reading27Regex reading28Name reading28Regex reading29Name reading29Regex reading30Name reading30Regex reading31Name reading31Regex reading32Name reading32Regex reading33Name reading33Regex requestHeader1<br />
attr Pollenflug group Pollenflug (Donnerwetter)<br />
attr Pollenflug reading01Name Erle<br />
attr Pollenflug reading01Regex (?s)Erle.*?poll([\d])<br />
attr Pollenflug reading02Name Hasel<br />
attr Pollenflug reading02Regex (?s)Hasel.*?poll([\d])<br />
attr Pollenflug reading03Name Löwenzahn<br />
attr Pollenflug reading03Regex (?s)L.wenzahn.*?poll([\d])<br />
attr Pollenflug reading04Name Gräser<br />
attr Pollenflug reading04Regex (?s)Gr.ser.*?poll([\d])<br />
attr Pollenflug reading05Name Gerste<br />
attr Pollenflug reading05Regex (?s)Gerste.*?poll([\d])<br />
attr Pollenflug reading06Name Linde<br />
attr Pollenflug reading06Regex (?s)Linde.*?poll([\d])<br />
attr Pollenflug reading07Name Beifuss<br />
attr Pollenflug reading07Regex (?s)Beifu.*?poll([\d])<br />
attr Pollenflug reading08Name Gansefuss<br />
attr Pollenflug reading08Regex (?s)Gansefu.*?poll([\d])<br />
attr Pollenflug reading09Name Mais<br />
attr Pollenflug reading09Regex (?s)Mais.*?poll([\d])<br />
attr Pollenflug reading10Name Brennessel<br />
attr Pollenflug reading10Regex (?s)Brennessel.*?poll([\d])<br />
attr Pollenflug reading11Name Hafer<br />
attr Pollenflug reading11Regex (?s)Hafer.*?poll([\d])<br />
attr Pollenflug reading12Name Roggen<br />
attr Pollenflug reading12Regex (?s)Roggen.*?poll([\d])<br />
attr Pollenflug reading13Name Weizen<br />
attr Pollenflug reading13Regex (?s)Weizen.*?poll([\d])<br />
attr Pollenflug reading14Name Spitzwegerich<br />
attr Pollenflug reading14Regex (?s)Spitzwegerich.*?poll([\d])<br />
attr Pollenflug reading15Name Raps<br />
attr Pollenflug reading15Regex (?s)Raps.*?poll([\d])<br />
attr Pollenflug reading16Name Hopfen<br />
attr Pollenflug reading16Regex (?s)Hopfen.*?poll([\d])<br />
attr Pollenflug reading17Name Holunder<br />
attr Pollenflug reading17Regex (?s)Holunder.*?poll([\d])<br />
attr Pollenflug reading18Name Ulme<br />
attr Pollenflug reading18Regex (?s)Ulme.*?poll([\d])<br />
attr Pollenflug reading19Name Pappel<br />
attr Pollenflug reading19Regex (?s)Pappel.*?poll([\d])<br />
attr Pollenflug reading20Name Weide<br />
attr Pollenflug reading20Regex (?s)Weide.*?poll([\d])<br />
attr Pollenflug reading21Name Birke<br />
attr Pollenflug reading21Regex (?s)Birke.*?poll([\d])<br />
attr Pollenflug reading22Name Eiche<br />
attr Pollenflug reading22Regex (?s)Eiche.*?poll([\d])<br />
attr Pollenflug reading23Name Esche<br />
attr Pollenflug reading23Regex (?s)Esche.*?poll([\d])<br />
attr Pollenflug reading24Name Platane<br />
attr Pollenflug reading24Regex (?s)Platane.*?poll([\d])<br />
attr Pollenflug reading25Name Flieder<br />
attr Pollenflug reading25Regex (?s)Flieder.*?poll([\d])<br />
attr Pollenflug reading26Name Ambrosia<br />
attr Pollenflug reading26Regex (?s)Ambrosia.*?poll([\d])<br />
attr Pollenflug reading27Name Buche<br />
attr Pollenflug reading27Regex (?s)Buche.*?poll([\d])<br />
attr Pollenflug reading28Name Rotbuche<br />
attr Pollenflug reading28Regex (?s)Rotbuche.*?poll([\d])<br />
attr Pollenflug reading29Name Ahorn<br />
attr Pollenflug reading29Regex (?s)Ahorn.*?poll([\d])<br />
attr Pollenflug reading30Name Nessel<br />
attr Pollenflug reading30Regex (?s)Nessel.*?poll([\d])<br />
attr Pollenflug reading31Name Kiefer<br />
attr Pollenflug reading31Regex (?s)Kiefer.*?poll([\d])<br />
attr Pollenflug reading32Name Tanne<br />
attr Pollenflug reading32Regex (?s)Tanne.*?poll([\d])<br />
attr Pollenflug reading33Name Fichte<br />
attr Pollenflug reading33Regex (?s)Fichte.*?poll([\d])<br />
attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)<br />
attr Pollenflug room Wetter-vorhersage<br />
</pre><br />
<br />
'''Erläuterung der Regex:'''<br />
<br />
HTTPMOD ruft einen riesigen Textblock ab. Darin sieht der relevante Abschnitt für "Hasel" wie folgt aus:<br />
<br />
<pre> Hasel</font></b></font></td> <td><img src="http://static.donnerwetter.de/images/poll0.gif" </pre><br />
<br />
Der reguläre Ausdruck dazu <br />
* sucht mit evtl. vorangegangenem Leerzeichen <code>(?s)</code><br />
* den Begriff <code>Hasel</code>,<br />
* lässt alles bis zum <code>poll</code> von poll0.gif aus und<br />
* liest die nachfolgende Dezimalzahl aus <code>([\d])</code> (bei poll0.gif also eine Null).<br />
<br />
<pre> (?s)Hasel.*?poll([\d]) </pre><br />
<br />
=== Daten darstellen ===<br />
[[Datei:pollenflug_balken.png|mini|200px]]<br />
Man kann die ausgelesenen Daten auf verschiedenste Weisen darstellen (vgl. auch die Links unten). Im folgenden ist eine einfache tabellarische Darstellung mit Hilfe einer [[ReadingsGroup]] beschrieben. Als kleines Schmankerl werden die Werte als Balken dargestellt (vgl. auch [[ReadingsGroup#Einfache_Balkendiagramme]]) und nur die Werte >0 dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]). <br />
<br />
<pre><br />
define rgPollenflug readingsGroup Pollenflug<br />
attr rgPollenflug mapping %READING<br />
attr rgPollenflug nolinks 1<br />
attr rgPollenflug notime 1<br />
attr rgPollenflug room Wetter-vorhersage<br />
attr rgPollenflug valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }<br />
attr rgPollenflug valueStyle { BalkenPollen($VALUE) }<br />
</pre><br />
<br />
Kurze Erläuterung:<br />
* <code>mapping %READING</code> Es wird der readingXXName in der Tabelle angezeigt.<br />
* <code>valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code> Werte = 0 (also kein Pollenflug) werden nicht dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]).<br />
* <code>valueStyle { BalkenPollen($VALUE) }</code> Der Balken wird über die Funktion "BalkenPollen" erzeugt (s.u.).<br />
<br />
Die notwendige Funktion für die [[99_myUtils_anlegen|99_myUtils.pm]] sieht wie folgt aus:<br />
<br />
<source lang="perl"><br />
# Balkenanzeige für Pollenflug<br />
sub BalkenPollen($) <br />
{<br />
my ($pollen) = @_;<br />
<br />
my $maxValue = 3;<br />
<br />
my $percent = $pollen / $maxValue * 100;<br />
<br />
my $color = "red";<br />
if ($pollen < 2) { $color = "yellow"; } <br />
elsif ($pollen < 3) { $color = "orange"; }<br />
<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Kurze Erläuterung (weitere Infos s. [[ReadingsGroup#Einfache_Balkendiagramme]]):<br />
* <code>$maxValue = 3</code> Donnerwetter liefert als Maximalwert 3 zurück.<br />
* <code>$color</code> Der Balken ist rot bei 3, orange bei 2, gelb bei 1.<br />
* <code>width: 200px;</code> Der Balken ist 200px breit.<br />
<br />
== Pollenkalender einbinden ==<br />
Einen statischen Pollenkalender als Grafik kann man bspw. wie folgt einbinden:<br />
define Pollenflug_Grafik_WD weblink image http://www.wetterdienst.de/imgs/pollenflugkalendar.jpg<br />
attr Pollenflug_Grafik_WD group Pollenflug (Wetterdienst)<br />
attr Pollenflug_Grafik_WD htmlattr width="50%" height="50%" frameborder="0" marginheight="0" marginwidth="0"<br />
attr Pollenflug_Grafik_WD room Wetter-vorhersage<br />
<br />
<br />
== Links ==<br />
* Foren-Diskussionen: [https://forum.fhem.de/index.php?topic=47769.0]<br />
* Bsp. auf Jürgens Technikwelt [http://www.juergenstechnikwelt.de/smarthome-2/smarthome-mit-fhem-pollenflug-aus-webseite-auslesen-und-im-tablet-ui-anzeigen/]<br />
* [[Wetter und Wettervorhersagen]]<br />
* Allergy-Modul im [https://forum.fhem.de/index.php?topic=37194.0 Forum]<br />
<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Wetterstationen]] <!-- eigentlich eine "Hardware-Kategorie", passt aber trotzdem --></div>Fabianhttp://wiki.fhem.de/w/index.php?title=Pollenflug&diff=15350Pollenflug2016-05-16T10:38:50Z<p>Fabian: /* Links */ Link zum Allergy-Modul eingefügt</p>
<hr />
<div>Genauso wie [[Wetter und Wettervorhersagen|Wettervorhersagen]], gibt es Pollenflug-Vorhersagen von verschiedensten Anbietern. Verschiedene Einbindungs- und Darstellungsmöglichkeiten sollen hier beschrieben werden.<br />
<br />
== Donnerwetter ==<br />
Die Daten können mit [[HTTPMOD]] aus der Donnerwetterseite ausgelesen werden. Als Voraussetzung benötigt man die konkrete URL. Dazu geht man einfach auf die [http://www.donnerwetter.de www.donnerwetter.de], sucht seine Stadt und wählt Pollenflug aus. Die URL dieser Seite wird nun ausgelesen.<br />
<br />
'''Anfänger-Tip:''' Das hier aufgeführte Bsp. kann mit nur einer einzigen Anpassung übernommen werden - und wenn Du in Berlin wohnst, brauchst Du garnichts anzupassen... ;-).<br />
<br />
=== Daten auslesen ===<br />
Der folgende Code liest sämtliche von Donnerwetter bereitgestellten Pollen-Informationen für Berlin aus. Wenn man nicht alle benötigt, kann man einfach die entsprechenden readingXXName und readingXXRegex weglassen. Der Abruf erfolgt täglich (alle 86400 Sekunden).<br />
<br />
'''Wichtig''' ist der Eintrag "attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)", ohne den HTTPMOD nur eine Fehlermeldung wirft.<br />
<br />
<pre><br />
define Pollenflug HTTPMOD http://www.donnerwetter.de/pollenflug/berlin/DE14356.html 86400<br />
attr Pollenflug userattr enableControlSet reading01Name reading01Regex reading02Name reading02Regex reading03Name reading03Regex reading04Name reading04Regex reading05Name reading05Regex reading06Name reading06Regex reading07Name reading07Regex reading08Name reading08Regex reading09Name reading09Regex reading10Name reading10Regex reading11Name reading11Regex reading12Name reading12Regex reading13Name reading13Regex reading14Name reading14Regex reading15Name reading15Regex reading16Name reading16Regex reading17Name reading17Regex reading18Name reading18Regex reading19Name reading19Regex reading20Name reading20Regex reading21Name reading21Regex reading22Name reading22Regex reading23Name reading23Regex reading24Name reading24Regex reading25Name reading25Regex reading26Name reading26Regex reading27Name reading27Regex reading28Name reading28Regex reading29Name reading29Regex reading30Name reading30Regex reading31Name reading31Regex reading32Name reading32Regex reading33Name reading33Regex requestHeader1<br />
attr Pollenflug group Pollenflug (Donnerwetter)<br />
attr Pollenflug reading01Name Erle<br />
attr Pollenflug reading01Regex (?s)Erle.*?poll([\d])<br />
attr Pollenflug reading02Name Hasel<br />
attr Pollenflug reading02Regex (?s)Hasel.*?poll([\d])<br />
attr Pollenflug reading03Name Löwenzahn<br />
attr Pollenflug reading03Regex (?s)L.wenzahn.*?poll([\d])<br />
attr Pollenflug reading04Name Gräser<br />
attr Pollenflug reading04Regex (?s)Gr.ser.*?poll([\d])<br />
attr Pollenflug reading05Name Gerste<br />
attr Pollenflug reading05Regex (?s)Gerste.*?poll([\d])<br />
attr Pollenflug reading06Name Linde<br />
attr Pollenflug reading06Regex (?s)Linde.*?poll([\d])<br />
attr Pollenflug reading07Name Beifuss<br />
attr Pollenflug reading07Regex (?s)Beifu.*?poll([\d])<br />
attr Pollenflug reading08Name Gansefuss<br />
attr Pollenflug reading08Regex (?s)Gansefu.*?poll([\d])<br />
attr Pollenflug reading09Name Mais<br />
attr Pollenflug reading09Regex (?s)Mais.*?poll([\d])<br />
attr Pollenflug reading10Name Brennessel<br />
attr Pollenflug reading10Regex (?s)Brennessel.*?poll([\d])<br />
attr Pollenflug reading11Name Hafer<br />
attr Pollenflug reading11Regex (?s)Hafer.*?poll([\d])<br />
attr Pollenflug reading12Name Roggen<br />
attr Pollenflug reading12Regex (?s)Roggen.*?poll([\d])<br />
attr Pollenflug reading13Name Weizen<br />
attr Pollenflug reading13Regex (?s)Weizen.*?poll([\d])<br />
attr Pollenflug reading14Name Spitzwegerich<br />
attr Pollenflug reading14Regex (?s)Spitzwegerich.*?poll([\d])<br />
attr Pollenflug reading15Name Raps<br />
attr Pollenflug reading15Regex (?s)Raps.*?poll([\d])<br />
attr Pollenflug reading16Name Hopfen<br />
attr Pollenflug reading16Regex (?s)Hopfen.*?poll([\d])<br />
attr Pollenflug reading17Name Holunder<br />
attr Pollenflug reading17Regex (?s)Holunder.*?poll([\d])<br />
attr Pollenflug reading18Name Ulme<br />
attr Pollenflug reading18Regex (?s)Ulme.*?poll([\d])<br />
attr Pollenflug reading19Name Pappel<br />
attr Pollenflug reading19Regex (?s)Pappel.*?poll([\d])<br />
attr Pollenflug reading20Name Weide<br />
attr Pollenflug reading20Regex (?s)Weide.*?poll([\d])<br />
attr Pollenflug reading21Name Birke<br />
attr Pollenflug reading21Regex (?s)Birke.*?poll([\d])<br />
attr Pollenflug reading22Name Eiche<br />
attr Pollenflug reading22Regex (?s)Eiche.*?poll([\d])<br />
attr Pollenflug reading23Name Esche<br />
attr Pollenflug reading23Regex (?s)Esche.*?poll([\d])<br />
attr Pollenflug reading24Name Platane<br />
attr Pollenflug reading24Regex (?s)Platane.*?poll([\d])<br />
attr Pollenflug reading25Name Flieder<br />
attr Pollenflug reading25Regex (?s)Flieder.*?poll([\d])<br />
attr Pollenflug reading26Name Ambrosia<br />
attr Pollenflug reading26Regex (?s)Ambrosia.*?poll([\d])<br />
attr Pollenflug reading27Name Buche<br />
attr Pollenflug reading27Regex (?s)Buche.*?poll([\d])<br />
attr Pollenflug reading28Name Rotbuche<br />
attr Pollenflug reading28Regex (?s)Rotbuche.*?poll([\d])<br />
attr Pollenflug reading29Name Ahorn<br />
attr Pollenflug reading29Regex (?s)Ahorn.*?poll([\d])<br />
attr Pollenflug reading30Name Nessel<br />
attr Pollenflug reading30Regex (?s)Nessel.*?poll([\d])<br />
attr Pollenflug reading31Name Kiefer<br />
attr Pollenflug reading31Regex (?s)Kiefer.*?poll([\d])<br />
attr Pollenflug reading32Name Tanne<br />
attr Pollenflug reading32Regex (?s)Tanne.*?poll([\d])<br />
attr Pollenflug reading33Name Fichte<br />
attr Pollenflug reading33Regex (?s)Fichte.*?poll([\d])<br />
attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)<br />
attr Pollenflug room Wetter-vorhersage<br />
</pre><br />
<br />
'''Erläuterung der Regex:'''<br />
<br />
HTTPMOD ruft einen riesigen Textblock ab. Darin sieht der relevante Abschnitt für "Hasel" wie folgt aus:<br />
<br />
<pre> Hasel</font></b></font></td> <td><img src="http://static.donnerwetter.de/images/poll0.gif" </pre><br />
<br />
Der reguläre Ausdruck dazu <br />
* sucht mit evtl. vorangegangenem Leerzeichen <code>(?s)</code><br />
* den Begriff <code>Hasel</code>,<br />
* lässt alles bis zum <code>poll</code> von poll0.gif aus und<br />
* liest die nachfolgende Dezimalzahl aus <code>([\d])</code> (bei poll0.gif also eine Null).<br />
<br />
<pre> (?s)Hasel.*?poll([\d]) </pre><br />
<br />
=== Daten darstellen ===<br />
[[Datei:pollenflug_balken.png|mini|200px]]<br />
Man kann die ausgelesenen Daten auf verschiedenste Weisen darstellen (vgl. auch die Links unten). Im folgenden ist eine einfache tabellarische Darstellung mit Hilfe einer [[ReadingsGroup]] beschrieben. Als kleines Schmankerl werden die Werte als Balken dargestellt (vgl. auch [[ReadingsGroup#Einfache_Balkendiagramme]]) und nur die Werte >0 dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]). <br />
<br />
<pre><br />
define rgPollenflug readingsGroup Pollenflug<br />
attr rgPollenflug mapping %READING<br />
attr rgPollenflug nolinks 1<br />
attr rgPollenflug notime 1<br />
attr rgPollenflug room Wetter-vorhersage<br />
attr rgPollenflug valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }<br />
attr rgPollenflug valueStyle { BalkenPollen($VALUE) }<br />
</pre><br />
<br />
Kurze Erläuterung:<br />
* <code>mapping %READING</code> Es wird der readingXXName in der Tabelle angezeigt.<br />
* <code>valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code> Werte = 0 (also kein Pollenflug) werden nicht dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]).<br />
* <code>valueStyle { BalkenPollen($VALUE) }</code> Der Balken wird über die Funktion "BalkenPollen" erzeugt (s.u.).<br />
<br />
Die notwendige Funktion für die [[99_myUtils_anlegen|99_myUtils.pm]] sieht wie folgt aus:<br />
<br />
<source lang="perl"><br />
# Balkenanzeige für Pollenflug<br />
sub BalkenPollen($) <br />
{<br />
my ($pollen) = @_;<br />
<br />
my $maxValue = 3;<br />
<br />
my $percent = $pollen / $maxValue * 100;<br />
<br />
my $color = "red";<br />
if ($pollen < 2) { $color = "yellow"; } <br />
elsif ($pollen < 3) { $color = "orange"; }<br />
<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Kurze Erläuterung (weitere Infos s. [[ReadingsGroup#Einfache_Balkendiagramme]]):<br />
* <code>$maxValue = 3</code> Donnerwetter liefert als Maximalwert 3 zurück.<br />
* <code>$color</code> Der Balken ist rot bei 3, orange bei 2, gelb bei 1.<br />
* <code>width: 200px;</code> Der Balken ist 200px breit.<br />
<br />
<br />
== Pollenkalender einbinden ==<br />
Einen statischen Pollenkalender als Grafik kann man bspw. wie folgt einbinden:<br />
define Pollenflug_Grafik_WD weblink image http://www.wetterdienst.de/imgs/pollenflugkalendar.jpg<br />
attr Pollenflug_Grafik_WD group Pollenflug (Wetterdienst)<br />
attr Pollenflug_Grafik_WD htmlattr width="50%" height="50%" frameborder="0" marginheight="0" marginwidth="0"<br />
attr Pollenflug_Grafik_WD room Wetter-vorhersage<br />
<br />
<br />
== Links ==<br />
* Foren-Diskussionen: [https://forum.fhem.de/index.php?topic=47769.0]<br />
* Bsp. auf Jürgens Technikwelt [http://www.juergenstechnikwelt.de/smarthome-2/smarthome-mit-fhem-pollenflug-aus-webseite-auslesen-und-im-tablet-ui-anzeigen/]<br />
* [[Wetter und Wettervorhersagen]]<br />
* Allergy-Modul im [https://forum.fhem.de/index.php?topic=37194.0 Forum]<br />
<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Wetterstationen]] <!-- eigentlich eine "Hardware-Kategorie", passt aber trotzdem --></div>Fabianhttp://wiki.fhem.de/w/index.php?title=ReadingsGroup&diff=15349ReadingsGroup2016-05-16T10:36:26Z<p>Fabian: /* Berechnungen */ Kap. "Readings löschen" eingefügt</p>
<hr />
<div>{{SEITENTITEL:readingsGroup}}<br />
{{Infobox Modul<br />
|ModPurpose=Einfache zusammenfassende Darstellung von Informationen über mehrere Geräte und deren Steuerung<br />
|ModType=h<br />
|ModCmdRef=readingsGroup<br />
|ModForumArea=Frontends<br />
|ModTechName=33_readingsGroup.pm<br />
|ModOwner=Andre ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:justme|Wiki]])}}<br />
<br />
Das Fhem-[[:Kategorie:Hilfsmodul|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.<br />
<br />
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.<br />
<br />
== Definition == <br />
Siehe [http://fhem.de/commandref.html#readingsGroup commandref].<br />
<br />
== Attribute ==<br />
{{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.}}<br />
Weitergehende Erläuterungen zu einzelnen Attributen.<br />
<br />
Die komplette Liste der Attribute ist der commandref zu entnehmen.<br />
<br />
=== noheading ===<br />
[[Datei:ReadingsGroup_noheading.png|mini|rechts|400px|ReadingsGroup: rechts mit "noheading" Attribut, links der anklickbare Titel]]<br />
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<br />
* <code>list TYPE=readingsGroup</code><br />
* einen "Probably associated with"-Link eines anderen Objekts oder über<br />
* manuelle Modifikation der URL eines anderen Objekts (<code>http:.../fhem?detail=<objektname></code>)<br />
erreichbar.<br />
<br />
=== nolinks ===<br />
Devicenamen und Titel der readingsGroup verlinken nicht mehr zur zugehörigen Detailansicht und sind nicht mehr anklickbar.<br />
<br />
=== nostate ===<br />
Das state-Reading wird bei regex match nicht berücksichtigt und nicht angezeigt.<br />
<br />
=== notime ===<br />
Es werden keine Timestamps für die Readings angezeigt. Nur für einspaltige readingsGroups sinnvoll.<br />
<br />
== Beispiele ==<br />
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.<br />
<br />
=== Einfache Auswahl über Reading-Namen ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define battStatus readingsGroup .*:[Bb]attery</code><br />
| Alle readings mit Namen '''Battery''' oder '''battery''' von allen Devices. <br />
| rowspan=3 | [[Datei:rgBattery.png|thumb]]<br />
|-<br />
| <code>attr battStatus alias FHT Batteriestatus </code><br />
| Der Alias wird als Zeilentitel verwendet<br />
|-<br />
| <code>attr battStatus mapping %ROOM </code><br />
| ''Mapping %ROOM'' führt dazu, dass der Raumname als Zeilentitel angezeigt wird.<br />
|}<br />
<br />
=== Übersicht HomeMatic Geräte ===<br />
<br />
<nowiki>define HM_Components readingsGroup <Gerät>,<Name>,<Model>,<S/N> TYPE=CUL_HM:+NAME,?model,D-serialNr</nowiki><br />
<br />
=== Auswahl über Reading-Namen, Status als Symbol dargestellt ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg_battery readingsGroup .*:battery</code><br />
| Alle readings mit Namen '''battery''' von allen Devices. <br />
| rowspan=4 | [[Datei:rgBattery2.png|thumb]]<br />
|-<br />
| <code>attr rg_battery alias Batteriestatus </code><br />
| Der Alias wird als Überschrift verwendet<br />
|-<br />
| <code>attr rg_battery valueIcon {'battery.ok' => 'batterie', 'battery.low' => 'batterie@red'}</code><br />
| Statt der reading Werte "ok" und "low" soll ein Icon angezeigt werden.<br />
|-<br />
|<code>attr rg_battery commands { "battery.low" => "set %DEVICE replaceBatteryForSec 60" }</code><br />
| Für LaCrosse devices kann man beim Klick auf ein rotes "battery low icon" direkt replaceBatteryForSec setzen.<br />
|}<br />
<br />
=== Reading-Werte zuordnen (Icon / Text) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define rg readingsGroup Contact.Dachboden_gross:sensed.*</code><br />
| Alle sensedreadings des Contact.Dachboden_gross device. <br />
| rowspan=4 | [[Datei:rgFenster.png|thumb]]<br />
|-<br />
| <code>attr rg mapping { 'sensed.A' => 'links', 'sensed.B' => 'rechts' }</code><br />
| Die Zuordnung rechts/links<br />
|-<br />
| <code>attr rg valueFormat {($VALUE eq '1')?"fts_window_roof":"fts_window_roof_open_2"}</code><br />
| Die Zuordnung von reading Wert zu Icon Namen.<br />
|-<br />
| <code>attr rg_battery valueIcon %VALUE </code><br />
| Statt des reading Werts soll ein Icon angezeigt werden.<br />
|}<br />
<br />
=== Formatvorgabe für Ausgabewerte ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define TempHygro readingsGroup TYPE=CUL_WS:temperature,humidity,dewpoint</code><br />
| Alle readings mit Namen '''temperature''', '''humidity''', '''dewpoint''' von allen Devices des Typs '''CUL_WS'''<br />
| rowspan=4 | [[Datei:rgTemperatur.png|thumb|[[S300TH]]-Werte in einer readingsGroup]]<br />
|-<br />
| <code>attr TempHygro alias Temperatur / rel. Feuchte / Taupunkt</code><br />
| Der Alias der readingsGroup wird als Überschrift verwendet<br />
|-<br />
| <code>attr TempHygro mapping %ALIAS</code><br />
| ''Mapping %ALIAS'' führt dazu, dass der Alias des Geräts als Zeilentitel angezeigt wird.<br />
|- <br />
| <code>attr TempHygro valueFormat { temperature => "%.1f&amp;deg;C", humidity => "%.1f %%", dewpoint => "%.1f&amp;deg;C"}</code><br />
| Formatierung der Ausgabewerte. '''Achtung:''' "%" die in der Ausgabe erscheinen sollen, müssen verdoppelt werden!<br />
|}<br />
<br />
=== Ausgabestil (hier rechtsbündig) ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Wetter readingsGroup WetterXXX:<%temp_temperature>,<Temperatur>,temperature WetterXXX:<%weather_humidity>,<Luftfeuchte>,humidity WetterXXX:<%weather_barometric_pressure>,<Luftdruck>,pressure<br />
</code><br />
| Die readings mit Namen '''temperature''', '''humidity''' und '''pressure''' vom Device WetterXXX jeweils mit einem Icon und einem Label davor.<br />
| rowspan=3 | [[Datei:rgWetter.png|thumb]]<br />
|-<br />
| <code>attr Wetter valueFormat { temperature => '%1.f &amp;deg;C', humidity => '%1.f %%', pressure => '%i mbar' }</code><br />
| Die Formatierung der Readingswerte<br />
|-<br />
| <code>attr Wetter valueStyle style="text-align:right"</code><br />
| Die Readings sollen rechtsbündig dargestellt werden.<br />
|}<br />
<br />
=== Internal Value ausgeben ===<br />
Diese Beispiel könnte entfallen (nächstes Beispiel ist sehr ähnlich; es wird lediglich ein weiterer Wert ausgegeben).<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI</code><br />
| 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.<br />
| rowspan=1 | [[Datei:rgculRSSI.png|thumb]]<br />
|}<br />
<br />
=== Internal Values ausgeben ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define culRSSI readingsGroup cul_RSSI=.*:+cul_RSSI,+cul_TIME</code><br />
| 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.<br />
| rowspan=2 | [[Datei:rgculRSSI2.png|thumb]]<br />
|-<br />
|attr culRSSI valueStyle {return undef if($READING =~ m/TIME/); ($VALUE <= -85)?'style="color:red"':($VALUE <= -80)?'style="color:yellow"':undef}<br />
|Schlechte RSSI Werte sollen abhängig von zwei Schwellwerten gelb oder rot eingefärbt werden (auf dem Screenshot nicht zu sehen).<br />
|}<br />
<br />
=== Alle Readings eines Gerätes, mit Ausnahme von... ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Systemstatus readingsGroup sysstat</code><br />
| Alle readings des sysstat Device<br />
| rowspan=4 | [[Datei:rgSysstat.png|thumb]]<br />
|-<br />
| <code>attr Systemstatus nostate 1</code><br />
| Ohne state<br />
|-<br />
| <code>attr Systemstatus notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Systemstatus mapping {'load' => 'Systemauslastung', 'temperature' => 'Systemtemperatur in &amp;deg;C'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|}<br />
<br />
=== Anzeige auf einem Floorplan ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define Heizung readingsGroup t(1|2|3):temperature</code><br />
| Die Temperatur readings der Devices t1, t2 und t3<br />
| rowspan=6 | [[Datei:rgHeizung.png|thumb|220px]]<br />
|-<br />
| <code>attr Heizung mapping {'t1.temperature' => 'Vorlauf', 't2.temperature' => 'R&amp;&uuml;cklauf', 't3.temperature' => 'Zirkulation'}</code><br />
| Die Zuordnung der reading Namen zu den Zeilentiteln<br />
|-<br />
| <code>attr Heizung nameStyle style="text-align:left"</code><br />
| Zeilentitel linksbündig wegen floorplan<br />
|-<br />
| <code>attr Heizung style style="font-size:20px;color:lightgray"</code><br />
| Großer Font und Farbe passend für den floorplan<br />
|-<br />
| <code>attr Heizung notime 1</code><br />
| Ohne readings timestamp<br />
|-<br />
| <code>attr Heizung valueFormat : %.1f &amp;deg;C</code><br />
| Doppelpunkt zwischen Zeilentitel und Wert, eine Nachkommastelle plus Einheit<br />
|}<br />
<br />
<br />
=== LightScene DropDown-Menü für smallscreen Styles oder Floorplan ===<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen !! Aussehen <br />
|-<br />
| style="width:40%" |<code>define lcDropDown readingsGroup meineLightScene:!state</code><br />
| Für die LightScene ''meineLightScene'' soll ein DropDown-Menü zur Auswahl der Szene erstellt werden.<br />
| rowspan=6 |<br />
|-<br />
| <code>attr lcDropDown commands { state => 'scene:' }</code><br />
| Die Anzeige des state Readings wird auf das DropDown-Menü für das scene Kommando gemapped.<br />
|-<br />
| <code>attr lcDropDown nonames 1</code><br />
| Keine Readingnamen<br />
|-<br />
| <code>attr lcDropDown notime 1</code><br />
| Kein Timestamp<br />
|}<br />
<br />
=== Schriftgrößen, Farben, Icons ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgVerbrauchPCA301.png|links|mini|400px|Schriftgröße, Farbe, Icons...]]<br />
|-<br />
| style="width:40%" |<code>define Verbrauch readingsGroup TYPE=PCA301:state,power,consumption</code><br />
| Die readings state, power und consumption aller [[PCA301 Funkschaltsteckdose mit Energieverbrauchsmessung|PCA301]] Devices mit einer Zeile pro Device. <br />
|-<br />
| <code>attr Verbrauch mapping %ROOM %ALIAS</code><br />
| Der Raumname und der Alias werden als Zeilentitel verwendet<br />
|-<br />
| <code>attr Verbrauch nameStyle style="font-weight:bold"</code><br />
| Der Zeilentitel soll fett sein<br />
|-<br />
| <code>attr Verbrauch style style="font-size:20px"</code><br />
| Alles in einem größeren Font<br />
|-<br />
| <code>attr Verbrauch valueFormat {power => "%.1f W", consumption => "%.2f kWh"}</code><br />
| Die Formatierung für die power und consumption readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>attr Verbrauch valueIcon { state => '%devStateIcon' }</code><br />
| Für die Dosen, die schaltbar sind, soll das anklickbare device icon gezeigt werden.<br />
|-<br />
|<code>attr Verbrauch valueStyle {($READING eq "power" && $VALUE > 40)?'style="color:red"':'style="color:green"'}</code><br />
|Wenn das power reading >40 ist, soll es in rot angezeigt werden, alle anderen Werte und readings in grün<br />
|}<br />
<br />
=== Wertabhängige Farbgebung ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:TemperaturenRG.png|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:TemperaturenRG2.png|600px|mini|links|Andere Werte - andere Farben]]<br />
|-<br />
| style="width:40%" |<code>define wzTemperaturenRG readingsGroup Aussen:,<Temperatur>,temperature,<Luftfeuchte>,humidity Wohnzimmer:,<Temperatur>,temperature,<Luftfeuchte>,humidity Kasten_E_Geraete:,<Temperatur>,temperature,<Luftfeuchte>,humidity</code><br />
| Die readings temperatur und humidity der Devices Aussen, Wohnzimmer und Kasten_E_Geraete in einer Zeile pro Device. <br />
|-<br />
| <code>attr wzTemperaturenRG group 3. Temperaturen</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzTemperaturenRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzTemperaturenRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzTemperaturenRG notime 1</code><br />
| notime<br />
|-<br />
| <code>attr wzTemperaturenRG valueFormat {temperature => "%.1f °C", humidity =>"%.1f %%" }</code><br />
| Die Formatierung für die temperatur und humidity readings: eine Nachkommastelle plus Einheit.<br />
|-<br />
|<code>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"'} }</code><br />
| Diverse Farbkombinationen sind möglich<br />
|}<br />
<br />
=== Enigma Receiver ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:ReceiverRG.jpg|600px|mini|links|Wertabhängige Farben]]<br />
[[Datei:ReceiverRGmute.jpg|600px|mini|links|Wertabhängige Farben]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| 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<br />
'''Benötigt:''' ENIGMA2 Receiver, 70_ENIGMA2.pm - Siehe: [[Enigma2 Receiver (Dreambox, VUplus etc.) steuern]]<br />
|-<br />
| <code>attr wzReceiverRG group Fernseher Receiver</code><br />
| Die readingsGroup kommt in eine Gruppe<br />
|-<br />
| <code>attr wzReceiverRG mapping &amp;nbsp;</code><br />
| mapping wird auf &amp;nbsp; (Leerzeichen) gesetzt, damit der Device Name nicht angezeigt wird<br />
|-<br />
| <code>attr wzReceiverRG noheading 1</code><br />
| noheading<br />
|-<br />
| <code>attr wzReceiverRG nostate 1</code><br />
| nostate<br />
|-<br />
| <code>attr wzReceiverRG notime 1</code><br />
| notime<br />
|-<br />
|-<br />
| <code>attr wzReceiverRG valueColumns { eventdescription => 'colspan="4"' }</code><br />
| Die Beschreibung soll über 4 Spalten gehen<br />
|-<br />
| <code>attr wzReceiverRG valueFormat { wzReceiverRGvalueFormat($DEVICE,$READING,$VALUE);; }</code><br />
| Die Formatierung wird in die 99_myUtils.pm ausgelagert. Siehe: [[99 myUtils anlegen]]<br />
|-<br />
|<code>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"' } }</code><br />
| Diverse Farbkombinationen sind möglich. Wenn der Receiver auf mute ist, wird anstatt der Lautstärke <span style="color: red;">mute</span> angezeigt.<br />
|-<br />
|<source lang="perl"><br />
sub<br />
wzReceiverRGvalueFormat($$$)<br />
{<br />
my ($DEVICE,$READING,$VALUE) = @_;<br />
<br />
if($READING eq 'hdd1_capacity') { <br />
return "%.2f MB";<br />
} elsif( $READING eq 'hdd1_free') {<br />
return "%.2f MB";<br />
} elsif( $READING eq 'volume' ) {<br />
if( ReadingsVal($DEVICE, "mute", "") eq "on") {<br />
return "mute";<br />
} else {<br />
return "%i %%";<br />
}<br />
}<br />
}</source><br />
| Dieser Teil kommt in die [[99_myUtils_anlegen|99_myUtils.pm]]<br />
|}<br />
<br />
=== Heizungswerte inklusive Batterie- und Fensterstatus ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung3.png|thumb|links|500px|Heizungswerte inklusive Batterie- und Fensterstatus]]<br />
|-<br />
| style="width:40%" |<code>define Heizungswerte readingsGroup <%sani_heating>,< >,<Act>,<Soll>,<Ist> TYPE=FHT:actuator,desired-temp,measured-temp,<%18>,<%20>,<%22>,window,battery</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte commands { 'Heizungswerte.18' => 'set $DEVICE desired-temp 18', 'Heizungswerte.20' => 'set $DEVICE desired-temp 20', 'Heizungswerte.22' => 'set $DEVICE desired-temp 22' }</code><br />
| Die Links/Kommandos die hinter den 18, 20 und 22 liegen sollen.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte inklusive Ventilposition ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:Rg_Heizung_Valveposition.png|thumb|links|500px|Heizungswerte inklusive Statusinformationen (MAX!)]]<br />
|-<br />
| 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><br />
| Diverse readings aller Devices des Typs <b>MAX</b>. <br />
|-<br />
| <code>attr Heizungswerte mapping %ROOM</code><br />
| Die Raumnamen werden angezeigt.<br />
|-<br />
| <code>attr Heizungswerte nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb (fett) sein.<br />
|-<br />
| <code>attr Heizungswerte room Heizung</code><br />
| Die "readingsgroup" wird dem Raum "Heizung" zugeordnet.<br />
|-<br />
| <code>attr Heizungswerte valueFormat {'temperature' => "%.0f °C", 'desiredTemperature' => "%.0f °C", 'valveposition' =>"%.0f %%", 'maxValveSetting' =>"%.0f %%" }</code><br />
| Es wird noch die Einheit °C hinter den Temperaturwerten angezeigt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriezustand werden Icons anstatt Klartextwerte genommen!<br />
|-<br />
| <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><br />
| Die Temperaturwerte werden abhängig vom Wert farbig dargestellt.<br />
|-<br />
| <code>attr Heizungswerte valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|}<br />
<br />
=== Heizungswerte, Status und Regelmöglichkeit ===<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung2.png|thumb|500px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| style="width:40%" |<code>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</code><br />
| Diverse readings aller Devices des Typs <b>FHT</b>. <br />
|-<br />
| <code>attr Heizungswerte2 nameStyle style="color:yellow;font-weight:bold"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr Heizungswerte2 valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red', 'window.closed' => 'fts_window_1w@lightgreen', 'window.open' => 'fts_window_1w_open@red'}</code><br />
| Für den Batteriestand und den Zustand der Fenster sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr Heizungswerte2 valueStyle {($VALUE eq "00")?'style="visibility:hidden"':''}</code><br />
| Nach dem Einstellen den Wert wieder ausblenden. <br />
|-<br />
| <source lang="perl"><br />
#Heizung regeln in readingsGroup<br />
sub<br />
myUtils_HeizungUpDown($$)<br />
{<br />
my($DEVICE,$CMD) = @_;<br />
<br />
my $icon = $CMD;<br />
my $VALUE = ReadingsVal($DEVICE,"desired-new","20" );<br />
$VALUE = ReadingsVal($DEVICE,"desired-temp","20" )<br />
if( !$VALUE || $VALUE == 0 );<br />
my $link;<br />
<br />
if( $CMD eq "up" ) {<br />
$icon = "control_arrow_upward";<br />
$VALUE += 1;<br />
<br />
if( $VALUE <= 24 ) {<br />
$icon .= "\@red";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
} elsif( $CMD eq "down" ) {<br />
$icon = "control_arrow_downward";<br />
$VALUE -= 1;<br />
<br />
if( $VALUE >= 18 ) {<br />
$icon .= "\@blue";<br />
$link = "setreading $DEVICE desired-new $VALUE";<br />
}<br />
}<br />
<br />
my $notify = "notifyHeizungUpDown";<br />
if( !defined($defs{$notify}) ) {<br />
CommandDefine(undef,<br />
"$notify notify .*:desired-new.* "<br />
."{ myUtils_HeizungUpDownNotify(\$NAME,\$EVTPART1); }" );<br />
}<br />
<br />
my $ret = "%$icon";<br />
$ret .= "%$link" if( $link );<br />
<br />
return $ret;<br />
}<br />
<br />
sub<br />
myUtils_HeizungUpDownNotify($$)<br />
{<br />
my($DEVICE,$VALUE) = @_;<br />
<br />
return if( $VALUE == 0 );<br />
<br />
my $at = "triggerHeizungUpDown_$DEVICE";<br />
CommandDelete(undef, $at) if( defined($defs{$at}) );<br />
CommandDefine(undef,<br />
"$at at +00:00:03 "<br />
."{my \$v = ReadingsVal(\"$DEVICE\",\"desired-new\",undef);"<br />
."fhem(\"set $DEVICE desired-temp \$v\") if( \$v );"<br />
."fhem(\"setreading $DEVICE desired-new 00\");}" );<br />
<br />
return undef;<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Heizungswerte, Status, Steuerung und Wochenprofil ===<br />
Dieses Beispiel funktioniert nur mit HomeMatic HM-CC-RT-DN, für andere Thermostate müssen an diversen Stellen Änderungen vorgenommen werden.<br />
{{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.}}<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgThermostate.png|thumb|750px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| style="width:40%" |<pre>set d_label Heizung Heizung <br />
set d_label Temperatur Temperatur <br />
set d_label Status Status <br />
set d_label Wochenplan Wochenplan <br />
set d_label Werktag Werktag <br />
set d_label Samstag Samstag <br />
set d_label Sonntag Sonntag <br />
set d_label Zeitraum1 Zeitraum 1 <br />
set d_label Zeitraum2 Zeitraum 2 </pre><br />
|Erzeugen der Readings im Device [[dummy#d_label|d_label]].<br />
|-<br />
| <code> <br />
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><br />
| 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]]. <br />
|-<br />
| <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><br />
| Temperaturen werden als DropDown Auswahl dargestellt, Icons triggern [[readingsGroup#sub_rg|ntfy_rg]]<br />
|-<br />
| <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><br />
| Ausblenden der Texte vor den DropDowns.<br />
|-<br />
| <code> <br />
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=""'}<br />
</code><br />
| Ausrichten der Überschriften die keine readings sind.<br />
|-<br />
| <code>attr rg_thermostate nonames 1</code><br />
| Ausblenden der Device Namen.<br />
|-<br />
| <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><br />
| Diverse Readings sollen über mehrere Spalten dargestellt werden.<br />
|-<br />
| <code>attr rg_thermostate valueFormat { 'measured-temp' => "%0.1f &deg;C", 'ValvePosition' => "%0.1f %%"}</code><br />
| Formatierung für measured-temp und ValvePosition.<br />
|-<br />
| <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><br />
| Zuweisung der Icons.<br />
|-<br />
| <code><br />
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"'}<br />
</code><br />
| Ausrichten und Einfärben der Readings.<br />
|}<br />
<br />
=== Heizungsteuerung für HM Wand- und Heizkörperthermostate ===<br />
<br />
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.<br />
Es werden Soll- und Ist-Temperaturen angezeigt, Luftfeuchte und Ventilpositionen, Modus, Batterie und Global-Tastenlock.<br />
Steuerungsmöglichkeiten: Solltemperatur, Modus (Manual/Automatik), (globale) Tastenlock.<br />
Die Abweichung der Isttemperatur, die Ventilpositionen, Batteriestand etc. werden farblich hervorgehoben. <br />
<br />
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.<br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:RgHMTh.jpg|thumb|500px|links|Status, Steuerung und Wochenprofil]]<br />
|-<br />
| <code>define heatingInfo readingsGroup <%sani_heating>,<Soll>,<Soll neu>,<Ist>,<Ventil / RH>,<Modus>,<Lock>,<Bat>\<br><br />
EG_WZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@EG_WZ_WT01,batteryLevel@EG_WZ_WT01 \<br><br />
EG_WZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT01,batteryLevel@EG_WZ_TT01 \<br><br />
EG_WZ_TT02_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@EG_WZ_TT02,batteryLevel@EG_WZ_TT02 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_BZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_BZ_WT01,batteryLevel@OG_BZ_WT01 \<br><br />
OG_BZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_BZ_TT01,batteryLevel@OG_BZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_SZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_SZ_WT01,batteryLevel@OG_SZ_WT01 \<br><br />
OG_SZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_SZ_TT01,batteryLevel@OG_SZ_TT01 \<br><br />
<>,<>,<>,<>,<>,<>,<>,<> \<br><br />
OG_DZ_WT01_Climate:desired-temp,<sollsetz>,measured-temp,humidity,controlMode,R-globalBtnLock@OG_DZ_WT01,batteryLevel@OG_DZ_WT01 \<br><br />
OG_DZ_TT01_Clima:desired-temp,<>,measured-temp,ValvePosition,controlMode,R-globalBtnLock@OG_DZ_TT01,batteryLevel@OG_DZ_TT01</code><br />
| ReadingsGoup anlegen. <br />
|-<br />
| <code>attr heatingInfo cellStyle { "r:1"=>'style="font-weight:bold;;font-size:16px"',<br><br />
"r:2,c:0"=>'style="font-weight:bold"',"r:6,c:0" =>'style="font-weight:bold"',<br><br />
"r:9,c:0"=>'style="font-weight:bold"',"r:12,c:0"=>'style="font-weight:bold"'}</code><br />
| Schrift fett setzen etc.<br />
|-<br />
| <code>attr heatingInfo commands {<br><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><br />
"controlMode.manual"=>"set %DEVICE controlMode auto","controlMode.auto"=>"set %DEVICE controlMode manual",<br><br />
"R-globalBtnLock.on"=>"set %DEVICE regSet globalBtnLock off",<br><br />
"R-globalBtnLock.off"=>"set %DEVICE regSet globalBtnLock on"}</code><br />
| Heizungssteuerung ermöglichen<br />
|-<br />
| <code><br />
attr heatingInfo mapping {OG_BZ_WT01_Climate=>"Bad",<br><br />
OG_BZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_SZ_WT01_Climate=>"Schlafzimmer",<br><br />
OG_SZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",OG_DZ_WT01_Climate=>"Duschbad",<br><br />
OG_DZ_TT01_Clima=>"&amp;nbsp;;&amp;nbsp;;&amp;nbsp;;Regler",EG_WZ_WT01_Climate=>"Wohnzimmer",<br><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><br />
</code><br />
| Gewünschte Namen definieren.<br />
|-<br />
| <code><br />
attr heatingInfo valueFormat {if($READING eq "ValvePosition" && $VALUE ne "0"){$VALUE = int($VALUE/10)*10}<br><br />
elsif($READING eq "batteryLevel"){if($VALUE>=3){$VALUE=100}<br><br />
elsif($VALUE>=2.7){$VALUE=75}elsif($VALUE>=2.5){$VALUE=50}elsif($VALUE>=2.2){$VALUE=25}<br><br />
else{$VALUE=0}}}<br />
</code><br />
| Werte vorformatieren (für die Icon-Zuordnung).<br />
|-<br />
| <code><br />
attr heatingInfo valueIcon {'controlMode.manual' => 'sani_heating_manual@795CFF',<br><br />
'controlMode.auto' => 'sani_heating_automatic@FFC13A', 'controlMode.boost' => 'sani_heating_boost@FB0C02',<br><br />
'humidity'=>'humidity@6FD9FB', 'R-globalBtnLock.on'=>'secur_locked@F7301D', <br><br />
'R-globalBtnLock.off'=>'secur_open@0CFB0C','ValvePosition.0' => 'sani_heating_level_0@002AE0',<br><br />
'ValvePosition.10' => 'sani_heating_level_10@F8D53D','ValvePosition.20' => 'sani_heating_level_20@FF9341',<br><br />
'ValvePosition.30' => 'sani_heating_level_30@F17F3F','ValvePosition.40' => 'sani_heating_level_40@E46C3C',<br><br />
'ValvePosition.50' => 'sani_heating_level_50@DE3B3A','ValvePosition.60' => 'sani_heating_level_60@A30D2D',<br><br />
'ValvePosition.70' => 'sani_heating_level_70@B40A23','ValvePosition.80' => 'sani_heating_level_80@C40619',<br><br />
'ValvePosition.90' => 'sani_heating_level_90@D4030F','ValvePosition.100' => 'sani_heating_level_100@E50005',<br><br />
'batteryLevel.100'=>'measure_battery_100@0CFB0C','batteryLevel.75'=>'measure_battery_75@42BC0A',<br><br />
'batteryLevel.50'=>'measure_battery_50@F5FF10','batteryLevel.25'=>'measure_battery_25@FB5909',<br><br />
'batteryLevel.0'=>'measure_battery_0@E50005','controlMode.set_boost' => 'hourglass',<br><br />
'controlMode.set_auto' => 'hourglass','controlMode.set_manual' => 'hourglass',<br><br />
'R-globalBtnLock.set_on' => 'hourglass','R-globalBtnLock.set_off' => 'hourglass'}<br />
</code><br />
| Icons zuordnen.<br />
|-<br />
| <code><br />
attr heatingInfo valueStyle {if($READING eq "measured-temp")<br><br />
{my $t=$VALUE;;my $d=ReadingsVal($DEVICE,'desired-temp',0);;<br><br />
if($t-$d>=1){'style="color:rgb(251,63,11);;"'}elsif($t-$d<=-1){'style="color:rgb(79,58,251);;"'}<br><br />
else{'style="color:rgb(12,251,12);;"'}}}<br />
</code><br />
| Farben (zu kalt: blau, zu warm: rot, ok: grün).<br />
|-<br />
| <code><br />
attr heatingInfo valueSuffix {"desired-temp"=>" °C", "measured-temp"=>" °C", <br><br />
"ValvePosition"=>" (".ReadingsVal($DEVICE,$READING,0)." %)", <br><br />
"humidity"=>" ".ReadingsVal($DEVICE,$READING,0)." % RH", <br><br />
"batteryLevel"=>" (".ReadingsVal($DEVICE,$READING,0)." V)"}<br />
</code><br />
| Messeinheiten und Zahlenwerte.<br />
|}<br />
<br />
=== Readings aus zusätzlichen Devices ===<br />
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.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rgHeizung4.png|thumb|750px|links|Anzeige + Regelmöglichkeit]]<br />
|-<br />
| 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><br />
| Diverse Readings aller Thermostat Devices und des jeweils zugehörigen Ventilantriebs. <br />
|-<br />
| <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><br />
| Die Benennung der Zeilentitel (Das ist je nach Konfiguration auch über $ALIAS und/oder $ROOM lösbar).<br />
|-<br />
| <code>attr myTemp commands { 'desired-temp' => 'desired-temp:' }</code><br />
| desired-temp soll per dropDown einstellbar sein.<br />
|-<br />
| <code>attr myTemp nameStyle style="color:yellow"</code><br />
| Die Überschriften sollen gelb sein.<br />
|-<br />
| <code>attr myTemp valueIcon {'battery.ok' => 'batterie@lightgreen', 'battery.low' => 'batterie@red'}</code><br />
| Für den Batteriestand sollen jeweils Icons angezeigt werden.<br />
|-<br />
| <code>attr myTemp valueFormat { 'measured-temp' => "%0.1f &amp;deg;C",'ToutIst' => "%.1f &amp;deg;C",'night-temp' => "%.1f &amp;deg;C",'day-temp' => "%.1f &amp;deg;C",'humidity' => "%.0f <br />
%%",'ValvePosition' => "%.0f %%",'ValveDesired' => "%.0f %%",'R-valveErrorPos' => "%.0f %%" }</code><br />
| Die Formatierung der Werte. <br />
|-<br />
|<source lang="perl"><br />
#namen des ventil device aus thermostat device ableiten<br />
sub valveOfDevice ($) {<br />
my ($DEVICE) = @_;<br />
<br />
if ($DEVICE =~ m/AZ/) {<br />
return "Ventil.".substr($DEVICE,11).".Nord";<br />
} else {<br />
return "Ventil.".substr($DEVICE,11); <br />
}<br />
}</source><br />
| 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.<br />
|}<br />
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><br />
<br />
=== Inhalte filtern ===<br />
Wenn man gewisse Zeilen einer Readingsgroup nicht dargestellt haben möchte, so kann man diese mit Hilfe von <code>valueFormat</code> ausfiltern, bspw.:<br />
<br />
<code>attr rg valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code><br />
<br />
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.<br />
<br />
Dies kann man noch weiter ausbauen und dynamische Auswahllisten erstellen (s. [[ReadingsGroup#Dynamische Inhalte]]).<br />
<br />
=== Dynamische Inhalte ===<br />
[[Datei:rgDynamic-1.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 1]]<br />
[[Datei:rgDynamic-2.png|mini|450px|readingsGroup mit umschaltbarem Inhalt 2]]<br />
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<br />
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.<br />
<br />
<pre><br />
define LXrg dummy<br />
attr LXrg group -<br />
attr LXrg setList mode1:on,off mode2:open,closed,tilted<br />
attr LXrg stateFormat 1=mode1 2=mode2<br />
attr LXrg webCmd mode1:mode2<br />
<br />
define rg readingsGroup Window.*:state Light.*:state<br />
attr rg group -<br />
attr rg valueFormat { return $VALUE if ( $VALUE eq ReadingsVal("LXrg","mode1","") || $VALUE eq ReadingsVal("LXrg","mode2","") );; return undef;;}<br />
<br />
define Watch_LX notify LX.*:.* {my $value = ReadingsVal($NAME,'state','');;;;fhem("setreading $NAME $value")}<br />
</pre><br />
<br />
=== Enable/Disable Button am Beispiel eines WeekdayTimer ===<br />
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 [http://forum.fhem.de/index.php/topic,23655.msg169141.html#msg169141 diesen Forumsbeitrag]) für alle Objekte, die das Fhem Attribut ''disable'' unterstützen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_scheduling.png|thumb|500px|links|Enable/Disable Button]]<br />
|-<br />
| 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><br />
| 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. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueFormat { if ( $READING =~ m/.*DEF/ ) { my @text = split(" ", $VALUE); shift @text; return join(" ", @text) }}</code><br />
| Der Name des Timers wird aus dem Internal "+DEF" vorne abgeschnitten. Damit werden nur die definierten Schaltpunkte angezeigt. <br />
|-<br />
| <code>attr rg_Timer_Wasser valueIcon { 'disabled.0' => 'Restart', 'disabled.1' => 'Shutdown' }</code><br />
| Die beiden Zustände für den Button werden durch zwei Standard-Icons angezeigt.<br />
|-<br />
| <code>attr rg_Timer_Wasser commands { 'disabled.0' => 'set $DEVICE disable', 'disabled.1' => 'set $DEVICE enable' }</code><br />
| Toggle-Funktion für den Button. Wenn der Timer aktiv ("disabled.0") sorgt ein Klick auf den Button, dass der Timer deaktiviert wird ("set $DEVICE disable").<br />
|-<br />
|<source lang="perl"><br />
sub rg_timer_Wasser_show_conditional($$)<br />
{<br />
my ($DEVICE,$READING) = @_;<br />
return ( ReadingsVal($DEVICE, "disabled", "1") eq "0" )? <br />
ReadingsVal($DEVICE, $READING, "reading_undef") : "disabled";<br />
}</source><br />
| 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.<br />
|}<br />
<br />
=== Ändern von Attributen: Noch ein WeekdayTimer Beispiel ===<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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 deaktiviert WeekdayTimer angezeigt. <br />
<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| colspan=2 | [[Datei:rg_timer.png|thumb|500px|links|FhemWidget für das 'disable' Attribut]]<br />
|-<br />
| style="width:40%" |<code>define rgTimer readingsGroup <>,<Current>,<Update-Time>,<New>,<disable> TYPE=WeekdayTimer:state,nextUpdate,nextValue,?!disable</code><br />
| 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. <br />
|-<br />
| <code>attr rgTimer valueIcon { state => '%devStateIcon', nextValue => '{(split(":",Color::devStateIcon($DEVICE,"dimmer",undef,"nextValue")))[1]}' }</code><br />
| Für den aktuellen Zustand wird das devStateIcon angezeigt und für den nächsten Zustand das passende Lampen-Icon.<br />
|-<br />
| <code>attr rgTimer_Wasser valueFormat '{(split(" ", $VALUE))[1]}'</code><br />
| Vom nächsten Schaltpunkt wird nur die Zeit angezeigt. <br />
|-<br />
| <code>attr rgTimer commands { disable => 'disable:' }</code><br />
| Für das disable attribut wird das normale dropDown mit 0 und 1 angezeigt das auch in der Device Detail Ansicht verwendet wird.<br />
|}<br />
<br />
=== Readings löschen ===<br />
Es kann vorkommen, dass Readings angezeigt werden, die garnicht existieren sollten - bspw. wenn man in einer HTTPMOD ein Reading umbeannt hat, kann auch der alte Readingsname immernoch angezeigt werden. Solche Readings können mit der globalen Funktion [http://fhem.de/commandref.html#deletereading deletereading] gelöscht werden.<br />
<br />
'''Achtung:''' Auf jeden Fall die [http://fhem.de/commandref.html#deletereading CommandRef dazu] lesen!<br />
<br />
Beispiel:<br />
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-Befehltszeile hat das veraltete Reading entfernt.<br />
<br />
<br />
== Berechnungen ==<br />
{{Randnotiz|RNTyp=y|RNText=Dieses Beispiel benutzt Funktionen, die erst ab [[version|Modulversion]] 8761/16.6.2015 verfügbar sind.}}<br />
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.<br />
<br />
Ein Beispiel:<br />
:<code>define rg readingsGroup .*:temperature rg:$avg</code><br />
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.<br />
<br />
Das genaue Format: <code>$<operator>[(<zellen>)]</code> mit<br />
*<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.<br />
*<code><zellen></code> ist eine durch Semikolon getrennte Liste aus <code><zeilen>:<spalten></code> Paaren. <br />
*<code><zeilen></code> und <code><spalten></code> sind jeweils eine Perl Liste, d.h. hier können <br />
** einzelne Werte,<br />
** durch Komma getrennte Aufzählungen,<br />
** mit .. angegebene Wertebereiche<br />
** sowie <code>$ROW</code> und <code>$COLUMN</code> als Bezeichner für die aktuelle Zelle<br />
:verwendet werden.<br />
<br />
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.<br />
<br />
Es ergeben sich somit unter anderem folgende Möglichkeiten:<br />
*<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.<br />
*<code>$max($ROW:1..$COLUMN-1)</code> Maximum aller Werte links von der aktuellen Zelle (in der aktuellen Zeile)<br />
*<code>$avg(1..$ROW:1)</code> Durchschnitt aller Werte in Spalte 1 bis zur aktuellen Zeile<br />
*<code>$scalar(:1)</code> Anzahl der Werte in Spalte 1<br />
*<code>$min(1..5:1,2,4)</code> Minimum der Werte aus den Zeilen 1-5 in den Spalten 1, 2 und 4<br />
<br />
Eigene Funktionen lassen sich über 99_myUtils anlegen und z.B. verwenden um Häufigkeiten zu zählen oder mit nichtnumerischen Readings umzugehen.<br />
<br />
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, ...<br />
<br />
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.<br />
<br />
Weitere Möglichkeiten:<br />
* 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.<br />
* special <code><nowiki><hr></nowiki></code> um eine horizontale Linie über die volle Breite einzufügen<br />
* Über ein angehängtes <code>@<alias></code> kann einem Rechenergebniss ein Alias-Name gegeben werden. Über diesen kann der Wert dann zur Formatierung mit den value-Attributen angesprochen werden.<br />
* 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.<br />
* Ü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.<br />
<br />
=== Ein interaktives Beispiel ===<br />
[[Datei:rgCalc.png|mini|right|400px|Beispiel-readingsGroup mit Berechnungen]]<br />
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 />
<br clear=all><br />
<pre><br />
define t1 dummy<br />
attr t1 room rg<br />
attr t1 setList state:slider,-10,1,30<br />
attr t1 webCmd state<br />
define t2 dummy<br />
attr t2 room rg<br />
attr t2 setList state:slider,-10,1,30<br />
attr t2 webCmd state<br />
define t3 dummy<br />
attr t3 room rg<br />
attr t3 setList state:slider,-10,1,30<br />
attr t3 webCmd state<br />
<br />
define rg readingsGroup <>,<value>,<sum>,<min>,<max>,<avg>\<br />
t\d:+NAME,state,$sum(1..$ROW:2),$min(1..$ROW:2),$max(1..$ROW:2),$avg(1..$ROW:2)\<br />
<hr>\<br />
rg:<>,$scalar,$sum(:2)@SUM,$min(:2)@MIN,$max(:2)@MAX,$avg(:2)@AVG\<br />
<hr>\<br />
t1:<t1,t2,t3>,state,state@t2,state@t3,$sum($ROW:2..4)@SUM,$count(/\d/)(2..$ROW-4:2)\<br />
<br />
attr rg nonames 1<br />
attr rg room rg<br />
attr rg style style='text-align:center'<br />
attr rg valueFormat { 'avg' => '%.2f', 'AVG' => '%.2f' }<br />
attr rg valuePrefix { 'rg.scalar' => '#', 'rg.SUM' =>'&Sigma;; ', 'rg.MIN' =>'Min: ', 'rg.MAX' =>'Max: ', 'rg.AVG' =>'&empty;; ', 'rg.count' => '#(X): ' }<br />
attr rg valueSuffix { state => '&deg;;C' }<br />
</pre><br />
<br />
== Links und Trigger ==<br />
=== readingsGroup mit Link ===<br />
[[Datei:rgPCA-detail.png|mini|400px|readingsGroup mit Link]]<br />
Das PCA301 Beispiel oben lässt sich mit einem ans Ende des define angehängten <br />
:<code><{appendTrigger($DEVICE,"clear","Alle löschen")}></code> <br />
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. <br />
:<code>define clearVerbrauch notify Verbrauch:clear set TYPE=PCA301 clear</code><br />
<br />
<source lang="perl"><br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
sub<br />
appendTrigger($$$)<br />
{<br />
my ($name,$trigger,$label) = @_; <br />
<br />
my $ret .= "</table></td></tr>";<br />
<br />
my $link = "cmd=trigger $name $trigger";<br />
my $txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$label</a>";<br />
$ret .= "<td colspan=\"99\"><div style=\"cursor:pointer;color:#888888;text-align:right\">$txt</div></td>";<br />
<br />
return ($ret,0);<br />
}</source><br />
<br />
wenn hierdurch Änderungen an einer readingsGroup erfolgen, die ein Neuladen der Seite erforderlich machen, kann dies so erfolgen:<br />
:<code>{myUtils_refresh("WEB")}</code><br />
mit folgendem code in 99_myUtils.pm:<br />
<source lang="perl"><br />
sub <br />
myUtils_refresh($) <br />
{ <br />
my ($name) = @_; <br />
<br />
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );<br />
}</source><br />
<br />
<br />
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.<br />
<br />
=== sub rg ===<br />
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.<br />
Anlegen des ntfy_rg notify<br />
<pre><br />
define ntfy_rg notify ntfy_rg {rg($EVENT)}<br />
</pre><br />
Folgender Code muss noch in de [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<source lang="perl"><br />
sub rg($){<br />
my @input = split(/[§\s]+/,shift);<br />
my $device = $input[0];<br />
my $function = $input[1];<br />
<br />
if($function eq "clima"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
<br />
return(("d_climaControl_".$room));<br />
}<br />
elsif($function eq "device"){<br />
return InternalVal($device,"device","device error");<br />
}<br />
elsif($function eq "controlMode"){<br />
my $controlMode = ReadingsVal($device,"controlMode","controlMode error");<br />
<br />
if($controlMode ~~ /manual/)<br />
{fhem("set $device controlMode auto")}<br />
elsif($controlMode ~~ /auto/)<br />
{fhem("set $device controlMode manual")};<br />
}<br />
elsif($function eq "globalBtnLock"){<br />
my $globalBtnLock = ReadingsVal($device,"R-globalBtnLock","globalBtnLock error");<br />
<br />
if($globalBtnLock ~~ /off/){<br />
{fhem("set $device regSet globalBtnLock on")}<br />
{fhem ("set $device getConfig")}<br />
}<br />
elsif($globalBtnLock ~~ /on/){<br />
{fhem("set $device regSet globalBtnLock off")}<br />
{fhem ("set $device getConfig")}<br />
};<br />
}<br />
elsif($function eq "state"){<br />
my $state = Value($device);<br />
<br />
if($state ~~ /off/){<br />
{fhem("set $device on")}<br />
}<br />
elsif($state ~~ /on/){<br />
{fhem("set $device off")}<br />
};<br />
}<br />
elsif($function eq "setTimeTable"){<br />
my $room = AttrVal($device, 'room', 'undef');<br />
$room =~ s/\D//g;<br />
my $climaControl = ("d_climaControl_".$room);<br />
my $dayTemp = ReadingsVal( $climaControl, "dayTemp" , 21.0 );<br />
my $nightTemp = ReadingsVal( $climaControl, "nightTemp" , 17.0 );<br />
my $workday_period_1_start = ReadingsVal( $climaControl, "workday_period_1_start" , "06:30" );<br />
my $workday_period_1_stop = ReadingsVal( $climaControl, "workday_period_1_stop" , "18:00" );<br />
my $workday_period_2_start = ReadingsVal( $climaControl, "workday_period_2_start" , "24:00" );<br />
my $workday_period_2_stop = ReadingsVal( $climaControl, "workday_period_2_stop" , "24:00" );<br />
my $saturday_period_1_start = ReadingsVal( $climaControl, "saturday_period_1_start" , "06:30" );<br />
my $saturday_period_1_stop = ReadingsVal( $climaControl, "saturday_period_1_stop" , "12:00" );<br />
my $saturday_period_2_start = ReadingsVal( $climaControl, "saturday_period_2_start" , "24:00" );<br />
my $saturday_period_2_stop = ReadingsVal( $climaControl, "saturday_period_2_stop" , "24:00" );<br />
my $sunday_period_1_start = ReadingsVal( $climaControl, "sunday_period_1_start" , "24:00" );<br />
my $sunday_period_1_stop = ReadingsVal( $climaControl, "sunday_period_1_stop" , "24:00" );<br />
my $sunday_period_2_start = ReadingsVal( $climaControl, "sunday_period_2_start" , "24:00" );<br />
my $sunday_period_2_stop = ReadingsVal( $climaControl, "sunday_period_2_stop" , "24:00" );<br />
<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
{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")};<br />
}<br />
}<br />
</source><br />
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.<br />
<br />
== Sonstiges ==<br />
In der Regel werden die Parameter zu einem reading in den mappings unter <$DEVICE> und dann <$DEVICE>.<$READING> und dann unter <$READING>.<$VALUE> gesucht.<br />
<br />
=== Lesbar machen ===<br />
Für die meisten Attribute gilt:<br />
<br />
* Wenn es komplexer wird ist es einfacher, den Code in eine eigene Routine in (beispielsweise) [[99 myUtils anlegen|99_myUtils]] auszulagern und diese aufzurufen:<br />
:<code> attr <name> valueStyle {myValueToFormat($READING,$VALUE)}</code><br />
* code für unterschiedliche readings kann auch im mapping schon aufgeteilt werden:<br />
:<code>attr <name> valueStyle { SuperE5 => '{perl code}', Diesel => '{perl code}' }</code><br />
* Ifs lassen sich verschachteln und sortieren. So kann die Anzahl der Klammern und Else-Zweige reduziert werden:<br />
if( $READING eq ... ) {<br />
return xxx if( $VALUE < 1 );<br />
return yyy if( $VALUE < 1.5 );<br />
return zzz;<br />
} elsif( $READING eq ... ) {<br />
...<br />
}<br />
<br />
Da alles lässt sich natürlich auch kombinieren und so viel lesbarer machen als ein einziger langer Bandwurm.<br />
<br />
=== readingsGroup in einer Gruppe ===<br />
Wenn der doppelte Rahmen um eine readingsGroup bei Darstellung in einer Gruppe stört, lässt er sich mit dem passenden style entfernen: <br />
:<code>attr <rgName> style style="border:0px;background:none;box-shadow:none"</code> <br />
Für die readingsGroup ''rgName'' wird der Darstellungsstil verändert.<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== Einfache Balkendiagramme ===<br />
[[Datei:rgBars.png|mini|400px|readingsGroup mit Balken]]<br />
Readings lassen sich mit einem valueStyle der folgenden Art mit einem "Füllstandsbalken" hinterlegen:<br />
:<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><br />
<br />
Die Balken werden bei Änderungen der Readings automatisch per longpoll aktualisiert.<br />
<br />
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. <br />
<br />
Deutlich flexibler ist eine Auslagerung als eigenständige Funktion in die [[99_myUtils_anlegen|99_myUtils.pm]], die den valueStyle dynamisch generiert, bspw.:<br />
<br />
<source lang="perl"><br />
sub Balkenanzeige($) <br />
{<br />
# Zuweisung der übergebenen Variablen<br />
my ($val) = @_;<br />
<br />
# Konfiguration des maximal übergebenen Werts (hier wäre der höchste zu erwartende Wert = 3)<br />
my $maxValue = 3;<br />
<br />
# Normalisierung auf 100%-Wert<br />
my $percent = $val / $maxValue * 100;<br />
<br />
# Definition des valueStyles<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,red '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
# Rückgabe des definierten Strings<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Der Aufruf sähe dann wie folgt aus:<br />
<br />
<code> attr <rgName> valueStyle { Balkenanzeige($VALUE) } </code><br />
<br />
Die einzelnen Werte des <code>$stylestring</code> haben folgende Bedeutungen:<br />
* width - Breite des Balkenrahmens<br />
* text-align - Ausrichtung des Texts<br />
* border - Format des Balkenrahmens<br />
* background-image - Format des Hintergrunds des Balkenrahmens, also des Balkens selbst<br />
** linear-gradient - css-Funktion zur Erstellung von Farbverläufen ''(*)''<br />
*** left - linksbündiger Balken<br />
*** red x% - roter Balken x% breit<br />
*** rgba(0,0,0,0) x% - farbloser Teil startet bei x%<br />
<br />
''(*) 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)''<br />
<br />
Weitere Infos zu:<br />
* linear-gradient - [https://developer.mozilla.org/de/docs/Web/CSS/linear-gradient]<br />
* Farbanpassungen, z.B. auch unter Verwendung der [[Color#Skalenfarbe_mit_Color::pahColor|Color::pahColor]] Routine.<br />
* Anpassung von Werten s.o. [[ReadingsGroup#Lesbar_machen]]<br />
* weiteren Möglichkeiten zur Erzeugung von Balkendiagrammen in Forenbeiträgen {{Link2Forum|Topic=25313|LinkText=hier}} und {{Link2Forum|Topic=28318|LinkText=hier}}<br />
* [[99_myUtils_anlegen|99_myUtils.pm]]<br />
<br />
Anwendungs-Bsp: [[Pollenflug]]<br />
<br />
=== readingsGroup Styling mit CSS ===<br />
Jede readingsGroup lässt sich durch CSS individuell stylen. <br />
<br />
==== Allgemeines ====<br />
Damit der eigene CSS Code nach einem [[Update]] der FHEM-Style Dateien vorhanden bleibt, ist es notwenig eine eigene .css Datei (zB ios7ReadingsGroups.css) zu erstellen und ins Verzeichnis ''fhem/www/pgm2/'' zu kopieren. Anschließend muss in der [[FHEMWEB]] Instanz das Attribut ''CssFiles'' auf zB ''pgm2/ios7ReadingsGroups.css'' gesetzt werden.<br />
<br />
==== Erweiterte Device Übersicht ====<br />
Diese ReadingsGroup ist an der [[FHEMWEB]] Device-Übersicht angelehnt. Zusätzlich werden weitere Readings, hier Leistung, Betriebszeit Heute und Jahr, ein Link zu Detail-Seite der ReadingsGroup und Links zu den jeweiligen Device-Detail-Seite, dargestellt.<br />
<br />
{| class="wikitable"<br />
| [[Datei:RgStylingOhneCss.png|600px|mini|left|Device ReadingsGroup ohne CSS]] [[Datei:RgStylingMitCss.png|600px|mini|left|Device ReadingsGroup mit CSS]]<br />
|}<br />
<br />
===== Definition =====<br />
<pre><br />
define rg_devices readingsGroup <{rgLink($DEVICE,"konfigurieren","Details")}>,<Device>,<Status>,<Leistung>,<Heute>,<Jahr>\<br />
wzDeckenfluter:<%light_floor_lamp>,<{rgLink("wzDeckenfluter","detail","Deckenfluter")}>,state,<>,dauerHeute,dauerJahr\<br />
wzMacMini:<%it_nas>,<{rgLink("wzMacMini","detail","MacMini")}>,state,power,consumption,consumptionYear\<br />
attr rg_devices noheading 1<br />
attr rg_devices nonames 1<br />
attr rg_devices notime 1<br />
attr rg_devices room ReadingsGroup Styling<br />
attr rg_devices style class="block wide rgDevices"<br />
attr rg_devices valueFormat { 'power' => "%.1f W ", consumption => "%.2f kWh", 'consumptionYear' => "%.2f kWh" }<br />
attr rg_devices valueIcon { state => '%devStateIcon' }<br />
</pre><br />
<br />
Damit sich der CSS auf die richtige readingsGroup bezieht, ist es nötigt <br />
das Attribut ''style'' anzupassen.<br />
{| class="wikitable"<br />
! Definition !! Erläuterungen <br />
|-<br />
| style="width:40%" |<code>attr <rgName> style class="block wide rgDevices"</code><br />
| Die Klassen ''block'' und ''wide'' müssen eingetragen werden. Der Name der Nachfolgenden Klasse, hier ''rgDevices'', ist frei wählbar.<br />
|}<br />
===== Funktion rgLink() =====<br />
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]].<br />
* $name - Name des Device das aufgerufen werden soll <br />
* $action - Aktion die Ausgeführt werden soll. <br />
**''konfigurieren'' erzeugt den kleinen ''Details'' Button links oben der einem zur Detail Seite der ReadingsGroup führt - nützlich wenn das ReadingsGroup-Attribut ''noheading'' gesetzt ist<br />
** ''detail'' erzeugt einen Link zu Device-Detail Seite<br />
* $label - Link-Name<br />
<source lang="perl"><br />
sub rgLink($$$){<br />
my ($name,$action,$label) = @_; <br />
my $link = "";<br />
my $fhemLink = "";<br />
my $txt = "";<br />
my $ret = "";<br />
my $divStyle = "";<br />
my $aStyle = "";<br />
<br />
# FHEM Variablen einbinden<br />
use vars qw($FW_ME);<br />
use vars qw($FW_subdir);<br />
use vars qw($FW_ss);<br />
use vars qw($FW_tp);<br />
<br />
if( $action eq "konfigurieren" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;font-size:11px;padding-bottom:2px;padding-left:3px;";<br />
}<br />
elsif( $action eq "detail" ){<br />
$fhemLink = "detail=$name";<br />
$divStyle = "cursor:pointer;display:inline;";<br />
}<br />
<br />
$link = '<a onclick="location.href=\'' . $FW_ME . $FW_subdir . '?' . $fhemLink . '\'" style="' . $aStyle . '">' . $label . '</a>';<br />
$txt = '<div style="' . $divStyle . '">' . $link . '</div>';<br />
$ret = "$txt";<br />
<br />
return $ret;<br />
}<br />
</source><br />
<br />
{{Randnotiz|RNText=Tipp<br />
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. }}<br />
<br />
===== Styling =====<br />
Die eigene .css Datei erscheint in FHEM unter Edit-Files --> styles und kann direkt im FHEM-Editor oder mit eigenen Editor bearbeitet werden.<br />
<br />
ios7ReadingsGroups.css:<br />
<pre><br />
/* Readings Groups Devices */<br />
table.rgDevices tr td{ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(2){ /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child{ /* 1. Spalte */ width: 45px; text-align: center; }<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 33%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
</pre><br />
<br />
==== Auf Portrait / Landscape Modus des Smartphone unterscheiden ====<br />
Dieses Beispiel ist an das obige Beispiel [[#Erweiterte_Device_.C3.9Cbersicht|Erweiterte Device Übersicht]] angelehnt. <br />
<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortrait.png|300px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscape.png|550px|mini|center|Device ReadingsGroup im Landscape Modus]]<br />
|}<br />
<br />
===== Allgemeines =====<br />
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<br />
<pre><br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) { }<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { }<br />
</pre><br />
<br />
===== Styling =====<br />
{{Randnotiz|RNText=Info<br />
* ''width: xx%'' ändert die Breite der Spalte<br />
* ''display: none'' blendet die Spalte aus}}<br />
In der FHEMWEB_phone Instanz muss wie [[#Allgemeines|hier]] beschrieben eine neue eigene .css Datei eingetragen werden. In diesem Beispiel ios7smallscreenReadingsGroups.css<br />
<br />
ios7smallscreenReadingsGroups.css<br />
<pre><br />
/* landscape und portrait modus */<br />
table.rgDevices tr td { /* Zuerst alles centern */ text-align: center; }<br />
table.rgDevices tr:first-child td:nth-child(1){ /* 1. Zeile 1. Spalte */ text-align: center; }<br />
table.rgDevices tr td:first-child { /* 1. Spalte */ width: 5%; }<br />
table.rgDevices tr:first-child td:nth-child(2) { /* 1. Zeile 2. Spalte */ text-align: center; }<br />
table.block table tr td table.rgDevices tr td { border-bottom: 1px solid #cbcbcb; }<br />
<br />
/* Portrait Modus */<br />
@media all and (orientation:portrait) {<br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 50%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: auto; text-align: right; display: table-cell; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 0; display: none; }<br />
table.rgDevices tr td:nth-child(6){ width: 0; display: none; } <br />
table.rgDevices tr td div a svg{ margin-left: 90px; }<br />
}<br />
<br />
/* Landscape Modus */<br />
@media all and (orientation:landscape) { <br />
table.rgDevices tr td:nth-child(2){ /* 2. Spalte */ width: 35%; text-align: left; }<br />
table.rgDevices tr td:nth-child(3){ /* 3. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(4){ /* 4. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; }<br />
table.rgDevices tr td:nth-child(5){ /* 5. Spalte */ width: 15%; } <br />
}<br />
</pre><br />
<br />
==== Plots im Portrait Modus des Smartphones ausblenden ====<br />
{| class="wikitable"<br />
| style="width:40%" |[[Datei:RgStylingSmallscreenPortraitPlot.png|350px|mini|center|Device ReadingsGroup im Portrait Modus]]<br />
|[[Datei:RgStylingSmallscreenLandscapePlot.PNG|550px|mini|center|Plot nur im Landscape]]<br />
|}<br />
<br />
Um die Plot und alle Steuerelemente im Portrait Modus auszublenden fügt man in seine eigene smallscreen.css wie [[#Allgemeines|hier beschrieben]] folgendes ein:<br />
<pre><br />
@media all and (orientation:portrait) {<br />
.SVGplot, .SVGlabel, .Zoom-in, .Zoom-out, .Prev { width: 0; display: none; }<br />
}<br />
</pre><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Code Snippets]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Fronthem_Installation&diff=15348Fronthem Installation2016-05-16T09:43:03Z<p>Fabian: Kategorien gesetzt</p>
<hr />
<div><br />
Einen Überblick über Fronthem findet man auf der Seite zu [[Fronthem]]<br />
<br />
== Allgemein ==<br />
=== Fhem ===<br />
Ein lauffähiges Fhem mit einem aktuellen Update sollte installiert sein.<br />
<br />
=== Webserver ===<br />
Für smartVISU muss ein Webserver (z.B. lighttpd oder Apache oder nginx) installiert sein.<br />
<br />
==== lighttpd ====<br />
<br />
sudo apt-get update<br />
sudo apt-get install lighttpd<br />
sudo apt-get install php5-common php5-cgi php5<br />
cd /var/www<br />
sudo lighty-enable-mod fastcgi-php<br />
sudo service lighttpd force-reload<br />
sudo chown www-data:www-data /var/www<br />
sudo chmod 775 /var/www<br />
sudo usermod -a -G www-data pi<br />
sudo usermod -a -G www-data bananapi<br />
<br />
==== nginx ====<br />
Folgende Pakete werden benötigt:<br />
$ apt-get install nginx php5-fpm<br />
<br />
Die Konfiguration für nginx kann man unter<br />
sudo nano /etc/nginx/sites-enabled/default<br />
vornehmen.<br />
<br />
Folgende Konfiguration sollte direkt funktionieren:<br />
server {<br />
listen 80;<br />
root /var/www;<br />
index index.html index.php;<br />
server_name localhost;<br />
location / {<br />
try_files $uri $uri/ /index.php?$args;<br />
}<br />
location ~ \.php$ {<br />
try_files $uri =404;<br />
fastcgi_pass unix:/var/run/php5-fpm.sock;<br />
fastcgi_index index.php;<br />
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;<br />
include fastcgi_params;<br />
}<br />
}<br />
<br />
== Installation smartVISU ==<br />
Die Installation stammt aus Jörg Herrmanns git-Repo: https://github.com/herrmannj/smartvisu-cleaninstall<br />
<br />
Folgende Pakete werden benötigt:<br />
$ apt-get install git<br />
<br />
Hierbei handelt es sich um das original smartVISU inkl. diverser Anpassungen (fhem-Treiber, ...).<br />
<br />
'''Download:'''<br />
$ mkdir ~/install<br />
$ cd ~/install<br />
$ git clone https://github.com/herrmannj/smartvisu-cleaninstall.git<br />
<br />
'''Installation:'''<br />
$ sudo cp -rp smartvisu-cleaninstall /var/www/smartvisu<br />
$ cd /var/www<br />
$ sudo chown -R www-data:www-data smartvisu<br />
<br />
'''Installation überprüfen:'''<br />
<br />
Beim Aufruf der Seite http://<IP-Adresse>/smartvisu sollte folgende Seite angezeigt werden: {{Randnotiz|RNTyp=y|RNText=Wenn ihr hier einen Fehler erhaltet und euch nicht die SmartVisu Seite angezeigt wird müsst ihr die Datei "config.ini.default" zu "config.ini" umbenennen, am besten erstellt ihr eine neue Kopie wie folgt:<br />
<code>$ sudo cp /var/www/smartvisu/config.ini.default /var/www/smartvisu/config.ini</code><br />
Ebenso bitte ggf. in der php.ini (error_reporting) die Ausgabe von Warnings abschalten, wenn so was kommt wie "Notice: Undefined index..."<br />
}}<br />
<br />
[[Datei:Installation_SmartVISU.png]]<br />
<br />
== Installation Fronthem ==<br />
Folgende Pakete werden benötigt:<br />
curl -L https://cpanmin.us | perl - --sudo App::cpanminus<br />
sudo cpanm Net::WebSocket::Server<br />
sudo cpanm JSON<br />
<br />
Mit folgendem Befehl kann man Fronthem installieren / updaten:<br />
update force https://raw.githubusercontent.com/herrmannj/fronthem/master/controls_fronthem.txt<br />
<br />
Konfiguration von Fronthem in Fhem (Eingabe in der Fhem Web Kommandozeile):<br />
define <Name Webservice> fronthem<br />
define <Name Endgerät> fronthemDevice <IP Endgerät><br />
<br />
Beispiel:<br />
define meinfronthem fronthem<br />
define meiniphone fronthemDevice 192.168.178.25<br />
<br />
"Save" nicht vergessen!<br />
Näheres dazu findet man auch unter http://www.fhemwiki.de/wiki/Fronthem#Basic_Syntax<br />
<br />
== Eigenes smartVISU Projekt anlegen ==<br />
* im Ordner "''/var/www/smartVISU/pages''" einen neuen Ordner "''MeinHaus"'' anlegen.<br />
* aus dem Ordner "''../pages/_template''" alles in den neuen Ordner ("''/var/www/smartVISU/pages/MeinHaus"'') kopieren.<br />
* "''rooms_menu.html''" an eigene Gegebenheiten anpassen hierzu dienen die "_template-Dateien" als Orientierung.<br />
* alle rooms anlegen durch Kopien des Beispielraumes (''room_sleeping.html'') und passende icons und Überschriften verteilen. ([http://www.smartvisu.de/docu/2.7/index.php?page=design/design_icons SmartVisu Icons])<br />
* SmartVISU nutzt [http://twig.sensiolabs.org/ Twig] als Template engine und die Seiten bestehen aus Blöcken und Widgets, die immer in doppelten geschweiften Klammern stehen <nowiki>{{ ... }}</nowiki><br />
* Widget Syntax auf [http://www.smartvisu.de/docu/2.7/index.php SmartVISU Doku] nachschlagen und kopieren.<br />
* innerhalb eines Raums zwischen {% block content %} und {% endblock %} als Beispiel folgenden Abschnitt einfügen:<br />
<br />
<pre><nowiki><br />
<h1><img class="icon" src='{{ icon0 }}scene_livingroom.png'/>Wohnzimmer</h1><br />
<div class="preblock"><br />
</div><br />
<div class="block"><br />
<div class="set-2" data-role="collapsible-set" data-theme="c" data-content-theme="a" data-mini="true"><br />
<div data-role="collapsible" data-collapsed="false" ><br />
<h3>Licht</h3><br />
<table width="90%"><br />
<tr><td align="left" width="100px">&nbsp;{{ basic.switch('Leselampe', 'Leselampe.sw', icon1~'light_floor_lamp.png', icon0~'light_floor_lamp.png') }}</td><br />
<td>Leselampe</td><br />
</tr><br />
</table><br />
</div><br />
</div><br />
</div><br />
</nowiki></pre><br />
<br />
* Datei speichern und checken, dass die Rechte mindestens auf "755" stehen, ansonsten mit "sudo chmod 755" korrigieren.<br />
* smartVISU aufrufen, Zahnrad = configmenü, eigenes Haus auswählen (Ordnername!) und als Treiber DOMOTIGA (oder auch FHEM) mit Port 2121 mit der IP des FHEM-Servers<br />
* speichern der Config nicht vergessen (Save ganz unten!)<br />
* jetzt ist es wichtig, dass ihr einmal eure Seiten in Smartvisu aufruft damit im Hintergrund die GADs erstellt werden.<br />
* In Fhem eure fronthemDevice Detailansicht öffnen<br />
* Nun seht ihr eure GADs, aus der gadliste ein gad auswählen (hier: "Leselampe.sw" wie im obigen Code-Beispiel definiert.) und die Parameter vergeben:<br />
<pre><br />
device: <fhem-Name-des-fhem-devices> (in diesem Fall die Leselampe.sw)<br />
reading: state<br />
converter: OnOff<br />
cmd set: state<br />
write: ja (haken setzen)<br />
read: ja (haken setzen)<br />
</pre><br />
: "state" immer klein schreiben und speichern nicht vergessen!<br />
* Die Settings für das Device gelten für alle Endgeräte, aber die read/write Rechte müssen für jedes Endgerät separat gesetzt werden.<br />
<br />
== Verbindung smartVISU mit Fhem ==<br />
=== Konfiguration smartVISU-Treiber ===<br />
==== Interface ====<br />
TODO<br />
<br />
==== I/O-Connection ====<br />
Unter smartVISU in die Konfigurationsoberfläche wechseln (http://<IP-Adresse>/smartvisu/index.php?page=config)<br />
<br />
Driver: ''Fhem'' (wird in Github von hermmanj bereitgestellt, falls smartvisu nicht von dort bezogen wird)<br />
<br />
Adresse: ''<IP-Adresse Fhem-Server>''<br />
<br />
Port: ''2121''<br />
<br />
== Bekannte Probleme ==<br />
TODO<br />
<br />
<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:FHEM Frontends]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=SNOM&diff=15347SNOM2016-05-16T09:40:33Z<p>Fabian: Kategorien gesetzt</p>
<hr />
<div>== Durchsage ==<br />
Ausgangslage: Ein FHEM mit funktionierender Sprachausgabe (Text2Speech) über den angeschlossenen Lautsprecher.<br />
Ziel: Die gleiche Durchsage auch auf allen SNOM 370 Telefonden abspielen.<br />
<br />
Da die Snom-Geräte Audiomulticast unterstützen kommt dieses hier zum Einsatz.<br />
<br />
Aktiviert wird es in den Einstellungen des Telefons. Hierzu muss am Telefon mit dem Knopf '''Settings''' das Einstellungsmenü aufgerufen werden. Hier kann man über den Eintrag '''Wartung''' und dann den Eintrag '''Administratormodus''' das Webfrontend freischalten.<br />
Nun geht es vom PC aus mit dem Browser weiter. Dazu die IP des Telefons eingeben und unter '''Ewetiert''' den Reiter '''SIP/RTP''' anwählen.<br />
Ganz unten gibt es nun eine Tabelle namens '''Multicast''' wo wir die '''Multicast Unterstützung''' auf '''An''' setzen. Darunter geben wir die Multicast IP Adresse sowie den dazugehörigen Port ein. Als Multicast IP kann man sich irgendwas im Range 224.0.0.0 - 239.255.255.255 aussuchen. Hier gibt es keine Abhängigkeit vom lokalen Subnetz - Wieso, Weshalb und Warum findet ihr in den RFC's [https://tools.ietf.org/html/rfc5771].<br />
<br />
Dann geht es auf dem Raspberry Pi weiter - hier benötigt man FFMPEG. Ihr müsst es selbst kompilieren da in dem raspian Paket keine Filter eingebaut sind. Dazu findet ihr alles unter [http://www.jeffreythompson.org/blog/2014/11/13/installing-ffmpeg-for-raspberry-pi/].<br />
<br />
Den ersten Test startet ihr mit folgendem Befehl: Bitte denkt daran die IP, den Port sowie die MP3 Datei (auf eine vorhandene) anzupassen.<br />
ffmpeg -re -i "/opt/fhem/cache/d08c473c8d5f7f1b7ac252ce80d0b12a.mp3" -filter_complex 'aresample=8000,asetnsamples=n=160,volume=0.25' -acodec pcm_mulaw -ac 1 -vn -f rtp rtp://IP:PORT<br />
<br />
Um es in FHEM aufrufen zu dürfen benötigt ihr einen SUDO Eintrag:<br />
fhem ALL=NOPASSWD: /usr/local/bin/ffmpeg *<br />
<br />
Unter FHEM ist es z.B. aus einem Notify wie folgt ansprechbar:<br />
system('ffmpeg -re -i /opt/fhem/"' . $value . '" -filter_complex "aresample=8000,asetnsamples=n=160,volume=0.25" -acodec pcm_mulaw -ac 1 -vn -f rtp rtp://IP:PORT');<br />
<br />
Damit das Text2Speech Modul ein passendes Notify abwirft müsst ihr an den Quellcode von dem Modul:<br />
Dazu öffnet ihr die Datei 98_Text2Speech.pm und springt auf Zeile 619 - Dass ist das Ende der Routine ''sub Text2Speech_BuildMplayerCmdString($$) {'' und fügt vor dem '''return $cmd;''' folgende Zeile ein:<br />
readingsSingleUpdate($hash, "file", $file, 1);<br />
Nun wird bei jedem Zusammenbau des Mplayer Kommandos der Dateiname an FHEM übergeben und kann dort über ein Notify ausgewertet werden.<br />
<br />
Nun noch das Notify anlegen:<br />
<br />
MyTTS {<br />
my $command = (substr($EVENT, 0, 4));;<br />
my $value = (substr($EVENT, 6,(length($EVENT)-1)));;<br />
Log 1, "$EVENT";;<br />
if($command eq "file") {<br />
Log 1, "$value";;<br />
system('ffmpeg -re -i /opt/fhem/"' . $value . '" -filter_complex "aresample=8000,asetnsamples=n=160,volume=0.25" -acodec pcm_mulaw -ac 1 -vn -f rtp rtp://IP:PORT');<br />
}<br />
}<br />
<br />
<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:Telefonie]]</div>Fabianhttp://wiki.fhem.de/w/index.php?title=Pollenflug&diff=15346Pollenflug2016-05-16T09:37:38Z<p>Fabian: Kategorien gesetzt (wie bei Wettervorhersagen), Link zu Wettervorhersagen gesetzt</p>
<hr />
<div>Genauso wie [[Wetter und Wettervorhersagen|Wettervorhersagen]], gibt es Pollenflug-Vorhersagen von verschiedensten Anbietern. Verschiedene Einbindungs- und Darstellungsmöglichkeiten sollen hier beschrieben werden.<br />
<br />
== Donnerwetter ==<br />
Die Daten können mit [[HTTPMOD]] aus der Donnerwetterseite ausgelesen werden. Als Voraussetzung benötigt man die konkrete URL. Dazu geht man einfach auf die [http://www.donnerwetter.de www.donnerwetter.de], sucht seine Stadt und wählt Pollenflug aus. Die URL dieser Seite wird nun ausgelesen.<br />
<br />
'''Anfänger-Tip:''' Das hier aufgeführte Bsp. kann mit nur einer einzigen Anpassung übernommen werden - und wenn Du in Berlin wohnst, brauchst Du garnichts anzupassen... ;-).<br />
<br />
=== Daten auslesen ===<br />
Der folgende Code liest sämtliche von Donnerwetter bereitgestellten Pollen-Informationen für Berlin aus. Wenn man nicht alle benötigt, kann man einfach die entsprechenden readingXXName und readingXXRegex weglassen. Der Abruf erfolgt täglich (alle 86400 Sekunden).<br />
<br />
'''Wichtig''' ist der Eintrag "attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)", ohne den HTTPMOD nur eine Fehlermeldung wirft.<br />
<br />
<pre><br />
define Pollenflug HTTPMOD http://www.donnerwetter.de/pollenflug/berlin/DE14356.html 86400<br />
attr Pollenflug userattr enableControlSet reading01Name reading01Regex reading02Name reading02Regex reading03Name reading03Regex reading04Name reading04Regex reading05Name reading05Regex reading06Name reading06Regex reading07Name reading07Regex reading08Name reading08Regex reading09Name reading09Regex reading10Name reading10Regex reading11Name reading11Regex reading12Name reading12Regex reading13Name reading13Regex reading14Name reading14Regex reading15Name reading15Regex reading16Name reading16Regex reading17Name reading17Regex reading18Name reading18Regex reading19Name reading19Regex reading20Name reading20Regex reading21Name reading21Regex reading22Name reading22Regex reading23Name reading23Regex reading24Name reading24Regex reading25Name reading25Regex reading26Name reading26Regex reading27Name reading27Regex reading28Name reading28Regex reading29Name reading29Regex reading30Name reading30Regex reading31Name reading31Regex reading32Name reading32Regex reading33Name reading33Regex requestHeader1<br />
attr Pollenflug group Pollenflug (Donnerwetter)<br />
attr Pollenflug reading01Name Erle<br />
attr Pollenflug reading01Regex (?s)Erle.*?poll([\d])<br />
attr Pollenflug reading02Name Hasel<br />
attr Pollenflug reading02Regex (?s)Hasel.*?poll([\d])<br />
attr Pollenflug reading03Name Löwenzahn<br />
attr Pollenflug reading03Regex (?s)L.wenzahn.*?poll([\d])<br />
attr Pollenflug reading04Name Gräser<br />
attr Pollenflug reading04Regex (?s)Gr.ser.*?poll([\d])<br />
attr Pollenflug reading05Name Gerste<br />
attr Pollenflug reading05Regex (?s)Gerste.*?poll([\d])<br />
attr Pollenflug reading06Name Linde<br />
attr Pollenflug reading06Regex (?s)Linde.*?poll([\d])<br />
attr Pollenflug reading07Name Beifuss<br />
attr Pollenflug reading07Regex (?s)Beifu.*?poll([\d])<br />
attr Pollenflug reading08Name Gansefuss<br />
attr Pollenflug reading08Regex (?s)Gansefu.*?poll([\d])<br />
attr Pollenflug reading09Name Mais<br />
attr Pollenflug reading09Regex (?s)Mais.*?poll([\d])<br />
attr Pollenflug reading10Name Brennessel<br />
attr Pollenflug reading10Regex (?s)Brennessel.*?poll([\d])<br />
attr Pollenflug reading11Name Hafer<br />
attr Pollenflug reading11Regex (?s)Hafer.*?poll([\d])<br />
attr Pollenflug reading12Name Roggen<br />
attr Pollenflug reading12Regex (?s)Roggen.*?poll([\d])<br />
attr Pollenflug reading13Name Weizen<br />
attr Pollenflug reading13Regex (?s)Weizen.*?poll([\d])<br />
attr Pollenflug reading14Name Spitzwegerich<br />
attr Pollenflug reading14Regex (?s)Spitzwegerich.*?poll([\d])<br />
attr Pollenflug reading15Name Raps<br />
attr Pollenflug reading15Regex (?s)Raps.*?poll([\d])<br />
attr Pollenflug reading16Name Hopfen<br />
attr Pollenflug reading16Regex (?s)Hopfen.*?poll([\d])<br />
attr Pollenflug reading17Name Holunder<br />
attr Pollenflug reading17Regex (?s)Holunder.*?poll([\d])<br />
attr Pollenflug reading18Name Ulme<br />
attr Pollenflug reading18Regex (?s)Ulme.*?poll([\d])<br />
attr Pollenflug reading19Name Pappel<br />
attr Pollenflug reading19Regex (?s)Pappel.*?poll([\d])<br />
attr Pollenflug reading20Name Weide<br />
attr Pollenflug reading20Regex (?s)Weide.*?poll([\d])<br />
attr Pollenflug reading21Name Birke<br />
attr Pollenflug reading21Regex (?s)Birke.*?poll([\d])<br />
attr Pollenflug reading22Name Eiche<br />
attr Pollenflug reading22Regex (?s)Eiche.*?poll([\d])<br />
attr Pollenflug reading23Name Esche<br />
attr Pollenflug reading23Regex (?s)Esche.*?poll([\d])<br />
attr Pollenflug reading24Name Platane<br />
attr Pollenflug reading24Regex (?s)Platane.*?poll([\d])<br />
attr Pollenflug reading25Name Flieder<br />
attr Pollenflug reading25Regex (?s)Flieder.*?poll([\d])<br />
attr Pollenflug reading26Name Ambrosia<br />
attr Pollenflug reading26Regex (?s)Ambrosia.*?poll([\d])<br />
attr Pollenflug reading27Name Buche<br />
attr Pollenflug reading27Regex (?s)Buche.*?poll([\d])<br />
attr Pollenflug reading28Name Rotbuche<br />
attr Pollenflug reading28Regex (?s)Rotbuche.*?poll([\d])<br />
attr Pollenflug reading29Name Ahorn<br />
attr Pollenflug reading29Regex (?s)Ahorn.*?poll([\d])<br />
attr Pollenflug reading30Name Nessel<br />
attr Pollenflug reading30Regex (?s)Nessel.*?poll([\d])<br />
attr Pollenflug reading31Name Kiefer<br />
attr Pollenflug reading31Regex (?s)Kiefer.*?poll([\d])<br />
attr Pollenflug reading32Name Tanne<br />
attr Pollenflug reading32Regex (?s)Tanne.*?poll([\d])<br />
attr Pollenflug reading33Name Fichte<br />
attr Pollenflug reading33Regex (?s)Fichte.*?poll([\d])<br />
attr Pollenflug requestHeader1 User-Agent: Mozilla/5.0 (Windows NT 6.0)<br />
attr Pollenflug room Wetter-vorhersage<br />
</pre><br />
<br />
'''Erläuterung der Regex:'''<br />
<br />
HTTPMOD ruft einen riesigen Textblock ab. Darin sieht der relevante Abschnitt für "Hasel" wie folgt aus:<br />
<br />
<pre> Hasel</font></b></font></td> <td><img src="http://static.donnerwetter.de/images/poll0.gif" </pre><br />
<br />
Der reguläre Ausdruck dazu <br />
* sucht mit evtl. vorangegangenem Leerzeichen <code>(?s)</code><br />
* den Begriff <code>Hasel</code>,<br />
* lässt alles bis zum <code>poll</code> von poll0.gif aus und<br />
* liest die nachfolgende Dezimalzahl aus <code>([\d])</code> (bei poll0.gif also eine Null).<br />
<br />
<pre> (?s)Hasel.*?poll([\d]) </pre><br />
<br />
=== Daten darstellen ===<br />
[[Datei:pollenflug_balken.png|mini|200px]]<br />
Man kann die ausgelesenen Daten auf verschiedenste Weisen darstellen (vgl. auch die Links unten). Im folgenden ist eine einfache tabellarische Darstellung mit Hilfe einer [[ReadingsGroup]] beschrieben. Als kleines Schmankerl werden die Werte als Balken dargestellt (vgl. auch [[ReadingsGroup#Einfache_Balkendiagramme]]) und nur die Werte >0 dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]). <br />
<br />
<pre><br />
define rgPollenflug readingsGroup Pollenflug<br />
attr rgPollenflug mapping %READING<br />
attr rgPollenflug nolinks 1<br />
attr rgPollenflug notime 1<br />
attr rgPollenflug room Wetter-vorhersage<br />
attr rgPollenflug valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }<br />
attr rgPollenflug valueStyle { BalkenPollen($VALUE) }<br />
</pre><br />
<br />
Kurze Erläuterung:<br />
* <code>mapping %READING</code> Es wird der readingXXName in der Tabelle angezeigt.<br />
* <code>valueFormat { return $VALUE if ( $VALUE > 0 );; return undef;; }</code> Werte = 0 (also kein Pollenflug) werden nicht dargestellt (vgl. auch [[ReadingsGroup#Inhalte_filtern]]).<br />
* <code>valueStyle { BalkenPollen($VALUE) }</code> Der Balken wird über die Funktion "BalkenPollen" erzeugt (s.u.).<br />
<br />
Die notwendige Funktion für die [[99_myUtils_anlegen|99_myUtils.pm]] sieht wie folgt aus:<br />
<br />
<source lang="perl"><br />
# Balkenanzeige für Pollenflug<br />
sub BalkenPollen($) <br />
{<br />
my ($pollen) = @_;<br />
<br />
my $maxValue = 3;<br />
<br />
my $percent = $pollen / $maxValue * 100;<br />
<br />
my $color = "red";<br />
if ($pollen < 2) { $color = "yellow"; } <br />
elsif ($pollen < 3) { $color = "orange"; }<br />
<br />
my $stylestring = 'style="<br />
width: 200px; <br />
text-align:center; <br />
border: 1px solid #ccc; <br />
background-image: -webkit-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -moz-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -ms-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: -o-linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%); <br />
background-image: linear-gradient(left,'.$color.' '.$percent.'%, rgba(0,0,0,0) '.$percent.'%);<br />
"';<br />
<br />
return $stylestring;<br />
}<br />
</source><br />
<br />
Kurze Erläuterung (weitere Infos s. [[ReadingsGroup#Einfache_Balkendiagramme]]):<br />
* <code>$maxValue = 3</code> Donnerwetter liefert als Maximalwert 3 zurück.<br />
* <code>$color</code> Der Balken ist rot bei 3, orange bei 2, gelb bei 1.<br />
* <code>width: 200px;</code> Der Balken ist 200px breit.<br />
<br />
<br />
== Pollenkalender einbinden ==<br />
Einen statischen Pollenkalender als Grafik kann man bspw. wie folgt einbinden:<br />
define Pollenflug_Grafik_WD weblink image http://www.wetterdienst.de/imgs/pollenflugkalendar.jpg<br />
attr Pollenflug_Grafik_WD group Pollenflug (Wetterdienst)<br />
attr Pollenflug_Grafik_WD htmlattr width="50%" height="50%" frameborder="0" marginheight="0" marginwidth="0"<br />
attr Pollenflug_Grafik_WD room Wetter-vorhersage<br />
<br />
<br />
== Links ==<br />
* Foren-Diskussionen: [https://forum.fhem.de/index.php?topic=47769.0]<br />
* Bsp. auf Jürgens Technikwelt [http://www.juergenstechnikwelt.de/smarthome-2/smarthome-mit-fhem-pollenflug-aus-webseite-auslesen-und-im-tablet-ui-anzeigen/]<br />
* [[Wetter und Wettervorhersagen]]<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Wetterstationen]] <!-- eigentlich eine "Hardware-Kategorie", passt aber trotzdem --></div>Fabianhttp://wiki.fhem.de/w/index.php?title=DbLog&diff=15345DbLog2016-05-16T09:29:59Z<p>Fabian: /* Fehler in Datenbank korrigieren */ Kapitel umbenannt</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />
}}<br />
<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen im fhem recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als [http://fhem.de/commandref_DE.html#FileLog FileLog] gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann Fhem die Log-Daten mittels [http://fhem.de/commandref_DE.html#DbLog DbLog] in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es 2 Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht gelogt werden sollen<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. [http://fhem.de/commandref_DE.html#event-on-update-reading commandref])<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
* current<br />
* history<br />
<br />
=== Tabellenlayout ===<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [http://sourceforge.net/p/fhem/code/HEAD/tree/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE 'history' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
CREATE TABLE 'current' (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Unter Ubuntu: <br />
apt-get install mysql-server mysql-client<br />
ob man die Pakete <br />
apt-get install libdbd-mysql libdbi1 libdbd-mysql-perl<br />
auch installieren muss, weiss ich nicht, bei mir sind sie drin<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
<br />
nun zu mysql verbinden:<br />
mysql -p -u root<br />
Enter password:<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann nach Bedarf in der Datei /opt/fhem/contrib/dblog/db_create_mysql.sql das Passwort und der Benutzername geändert werden.<br />
Dann wird die Datei eingelesen: <br />
<br />
#mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
#mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
vim /opt/fhem/contrib/dblog/db.conf<br />
<br />
Dann Fhem neustarten/rereadcfg (Wenns jemand sicher weiss, bitte ändern) halt dass die neue Config übernommen wird.<br />
Jetzt kann ein DbLog-Device angelegt werden: <br />
define logdb DbLog ./contrib/dblog/db.conf .*:.* # loggt ALLES!<br />
Als State muss ein "connected" angezeigt werden. <br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<source lang="sql"><br />
#mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from current; # Achtung, kann sehr groß werden .... #<br />
</source><br />
<br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_SplitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
Weitere Informationen siehe hier: [[DevelopmentModuleIntro#X_DbLog_splitFn]]<br />
<br />
<br />
== Bekannte Probleme ==<br />
Beim Anlegen der Datenbank per script wird die Value-Spalte nur als Varchar(32) definiert. Dieses kann dazu führen, dass besonders lange Readings (z.b. vom Modul sysmon) abgeschnitten werden und nicht in der Datenbank landen. Dieses lässt sich leicht beheben, indem man die Spalte auf Varchar(64) ändert (siehe auch {{Link2Forum|Topic=25648|Message=252433|LinkText=diesen Forenbeitrag}}).<br />
<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor den fhem ausmacht um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden ohne den fhem abschalten zu müssen. <br />
<br />
Datenbanken kann man ohne weiter Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt fhem stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
fhem wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]</div>Fabian