Vorsicht

Dies ist die Dokumentation des aktuellen Entwicklungszweigs der CometVisu. Es besteht daher die Möglichkeit, dass einige der hier beschriebenen Features mit dem aktuellsten Release der CometVisu nicht genutzt werden können.

Mapping

Hinweis

Die Funktionalität der Mappings in der Tile-Struktur unterscheidet nicht nicht wesentlich von den Mappings in der Pure-Struktur. Lediglich der Name des Elements in der Konfigurationsdatei ist anders: <cv-mapping>. Dennoch können Mappings aus einer alten Config nicht einfach übernommen werden, da die Widgets in der Tile-Struktur zum Teil mit den gemappten Werten nichts anfangen können.

Mit dem Element „cv-mapping“ können verschiedene Werte, die auf dem Bus gesendet werden für die Visualisierung unterschiedliche Bezeichnungen bekommen. Als einfachstes Beispiel kann z.B. eine angezeigte „0“ als „Aus“ dargestellt werden, währenddessen die „1“ mit „Ein“ bezeichnet werden kann. Hierbei können die Begriffe („An“, „Aus“ …) beliebig gewählt werden. Mapping ist Bestandteil der <cv-meta>-Sektion im XML. Die Mapping-Definition bekommt einen eindeutigen Namen, auf den man sich im späteren Verlauf für die unterschiedlichsten Visualisierungselemente beziehen kann.

Mapping von Werten zu Text

Eine einfache Definition im Meta-Bereich sieht folgendermaßen aus:

<cv-mapping name="AusAn">
  <entry value="0">Aus</entry>
  <entry value="1">An</entry>
</cv-mapping>

Dies würde bei Benutzung mit z.B. einem Info-Widget

Statt 0 und 1:

../../../_images/cv-value-nomapping-off.png
../../../_images/cv-value-nomapping-on.png

An und Aus anzeigen:

../../../_images/cv-value-mapping-off.png
../../../_images/cv-value-mapping-on.png

Die Farbe kann durch die Definition des Stylings bestimmt werden.

Mapping von Werten in Icons

Sofern ein Status per Icon angezeigt werden soll, kann man ein Mapping benutzen, um statt Werten (z.B. 0 oder 1) Icons anzuzeigen.

Die Definition im Meta-Bereich sieht dann folgendermaßen aus:

...
<cv-meta>
    <cv-mapping name="light">
        <entry value="1">ri-lightbulb-fill</entry>
        <entry value="0">ri-lightbulb-line</entry>
    </cv-mapping>
    <cv-styling name="button">
        <entry value="1">active</entry>
        <entry value="0">inactive</entry>
    </cv-styling>
</cv-meta>
...
<cv-switch mapping="light" styling="button">
    <cv-address slot="address" transform="DPT:1.001">1/4/0</cv-address>
    <span slot="primaryLabel">Schalter</span>
    <span slot="secondaryLabel">Ein/Aus</span>
</cv-switch>

So würde bei Benutzung mit z.B. einem Switch-Widget, je nach Status unterschiedliche Icons angezeigt:

Switch off
Switch on

Die Farbe der Icons wird hierbei über das Styling gesteuert.

Mapping von nicht-binären Werten

Mapping funktioniert nicht nur bei binären Datentypen. Ein Türkontakt liefert 0 bei geschlossener Tür, 1 bei offener Tür und 2 bei gekippter Tür. Das Mapping ersetzt die wenig aussagekräftige Zahl durch die entsprechenden Icons aus dem bei der CometVisu mitgeliefertem KNX User Forum Iconset

../../../_images/mapping_door_closed1.png
../../../_images/mapping_door_open1.png
../../../_images/mapping_door_tilt1.png
...
<cv-meta>
    <cv-mapping name="AufZuTuerSymbol">
        <entry value="0">knxuf-fts_door</entry>
        <entry value="1">knxuf-fts_door_open</entry>
        <entry value="2">knxuf-fts_door_tilt</entry>
    </cv-mapping>
    <cv-styling name="AufZuTuer">
        <entry value="0">green</entry>
        <entry value="1">red</entry>
        <entry value="2">orange</entry>
    </cv-styling>
</cv-meta>
...
<cv-widget>
    <cv-tile>
        <cv-row colspan="3" row="first">
            <label class="secondary">Haustür</label>
        </cv-row>
        <cv-row colspan="3" row="2">
            <cv-value mapping="AufZuTuerSymbol" styling="AufZuTuer">
                <cv-address transform="DPT:4.001" mode="read">1/1/0</cv-address>
                <cv-icon class="value" size="xxx-large"/>
            </cv-value>
        </cv-row>
    </cv-tile>
</cv-widget>

Wertebereiche

Es können auch Wertbereiche für die entsprechende Darstellung gewählt werden:

<cv-mapping name="Vorzeichen">
  <entry range-min="-1e99" range-max="0">Negativ</entry>
  <entry value="0">Null</entry>
  <entry range-min="0" range-max="1e99">Positiv</entry>
</cv-mapping>

Bei genauer Betrachtung sieht man, dass die „0“ drei mal vorkommt. Hier gilt die Regel, dass alle Werte, die Einzeldefinitionen haben, höher priorisiert werden, als die Werte innerhalb eines Wertebereichs. Dadurch ist es möglich, für einzelne Werte Sonderbezeichnungen (in diesem Fall die „Null“) zu definieren.

Besondere Mapping-Werte

Es gibt zwei Mapping Werte die gesondert behandelt werden:

  • NULL: wird angewendet, wenn der Wert leer ist

  • *: wird angewendet, wenn kein vorher definiertes Mapping für den Wert gefunden wurde

<cv-mapping name="Fehler">
    <entry value="NULL">Fehler</entry>
    <entry value="*">Ok</entry>
</cv-mapping>

Liefert das Backend keine Wert, liefert das Mapping den Wert Fehler zurück, ansonsten Ok.

Formeln (Einsteiger)

Manchmal ist es auch nötig, Werte vor der Darstellung umzurechnen, z.B. um andere Einheiten zu benutzen.

„x“ ist der Eingangswert, den die Formel passend modifiziert auf den Wert „y“ zuweisen muss.

Komplexere Funktionen und Berechnungen mit mehreren Werten können hier nicht durchgeführt werden, dafür muss eine externe Logik Engine (linknx o.ä.) eingesetzt werden. Allerdings ist es durchaus möglich, die gegebenen JavaScript-Funktionen zu verwenden. Mehr dazu weiter unten.

<cv-mapping name="Umrechnen_kW">
  <formula>y = x*1000</formula>
</cv-mapping>

Beispielsweise kann man damit °C in °F umrechnen:

../../../_images/mapping_formula.png
...
<cv-meta>
    <cv-mapping name="C-to-F">
        <formula>y = x*1.8+32</formula>
    </cv-mapping>
</cv-meta>
...
<cv-group open="true">
    <cv-info format="%.1f C">
        <cv-address slot="address" mode="read" transform="DPT:9.001">3/6/0</cv-address>
        <span slot="label">Aussentemperatur</span>
    </cv-info>
    <cv-info format="%.1f F" mapping="C-to-F">
        <cv-address slot="address" mode="read" transform="DPT:9.001">3/6/0</cv-address>
        <span slot="label">Aussentemperatur</span>
    </cv-info>
</cv-group>

Mit diesem Beispiel können fehlerhafte Sensoren in einer Übersichtsseite markiert werden. Sensoren liefern in der Regel nummerische Werte. Bleiben diesen aus, kann z.B. das expire-Binding in openHAB einen negativen Wert zurückliefern. Das Mapping würde ein OK oder not OK liefern:

../../../_images/mapping-sensor-alarm-ok.png
../../../_images/mapping-sensor-alarm-notok.png
...
<cv-meta>
    <cv-mapping name="SensorAlarm">
        <formula>y = (x &gt;= 0) ? "OK" : "not OK";</formula>
    </cv-mapping>
</cv-meta>
...
<cv-info mapping="SensorAlarm">
    <cv-address slot="address" mode="read" transform="DPT:9.001">3/6/0</cv-address>
    <span slot="label">BWM WZ</span>
</cv-info>

Formeln (Advanced)

Wenn bekannt ist, um welchen exakten Objekt-Typ es sich handelt, können in einer Formel auch die konkreten JavaScript-Methoden verwendet werden.

Wird bspw. openHAB als Backend verwendet, gibt es dort den Item-Type DateTime. Dieser Datentyp wird auf das JavaScript-Gegenstück gemappt, so dass dessen Methoden direkt angewendet werden können.

Ohne Mapping resp. Formel sieht der Output eines openHAB-DateTime-Items bspw. so aus:

../../../_images/mapping-oh-datetime.png
<cv-info format="%s Uhr" value-size="normal">
    <cv-address slot="address" transform="OH:datetime">Sunrise_Time</cv-address>
</cv-info>

Möchte man jedoch lediglich die Uhrzeit im Output haben, so geht das mit folgendem Mapping:

../../../_images/mapping_oh_time.png
...
<cv-meta>
    <cv-mapping name="HourMinute">
        <formula>y = x &amp;&amp; x.constructor === Date ? x.getHours() + ':' + x.getMinutes() : x;</formula>
    </cv-mapping>
</cv-meta>
...
<cv-info format="%s Uhr" mapping="HourMinute" value-size="normal">
    <cv-address slot="address" transform="OH:datetime">Sunrise_Time</cv-address>
</cv-info>

Vorsicht

Die OH-Datentypen sind vollständig in Kleinbuchstaben definiert! Das muss in der CV-Konfig auch so geschrieben werden, sonst wird das Mapping nicht funktionieren. DateTime ist nicht gleich datetime!

Der openHAB-DateTime-Datentyp wird auf ein JavaScript-Date gemappt. Hier findet sich die Referenz der verfügbaren JavaScript-Methoden, welche man auf diesem Objekt aufrufen kann.

Formeln mit lokalem Store

Eine Besonderheit, die momentan nur für <cv-button> implementiert ist, ist das Benutzen eines Wertspeichers (Store) innerhalb einer Formel. Das ermöglicht es in der Formel Berechnungen durchzuführen, die von mehreren Status-Werten abhängen. Möchte man z.B. berechnen wie viel Prozent eines Lieds bereits abgespielt wurde benötigt man die aktuelle Position im Song und die gesamte Spielzeit, um den Prozentwert berechnen zu können.

 <cv-button class="round-button" mapping="tile-play-stop" progress-mapping="tile-play-progress">
    <cv-address transform="DPT:1.001">1/4/0</cv-address>
    <cv-address transform="DPT:5.010" mode="read" target="progress">1/4/1</cv-address>
    <cv-address transform="DPT:5.010" mode="read" target="store">1/4/2</cv-address>
    <cv-icon class="value">ri-stop-fill</cv-icon>
</cv-button>

Die Adresse 1/4/1 liefert die aktuelle Position im Lied in Sekunden und wird für den Fortschrittsbalken benutzt (target="progress"). Die Adresse 1/4/2 liefert die Gesamtdauer des Liedes und wird in dem Wertspeicher abgelegt (target="store"). Der Wertspeicher ist eine Javascript Map und benutzt die Adresse als Schlüssel um den letzten Wert vom Bus zu speichern (z.B. {"1/4/2": 240}).

Dieser Wert kann nun im Mapping für den Fortschrittsbalken genutzt werden (progress-mapping="tile-play-progress")

<cv-mapping name="tile-play-progress">
    <formula>
        d = store.get('1/4/2');
        y = d > 0 ? Math.round(100/d*x) : 0;
    </formula>
</cv-mapping>

Möchte man einen aussagekräftigeren Namen als die Gruppen-Adresse für den Store benutzen, so kann man diesen mit angeben: <cv-address transform="DPT:5.010" mode="read" target="store:duration">1/4/2</cv-address>. In diesem Fall würde die Zeile im Mapping die diesen Wert ausliest dann so aussehen d = store.get('duration');.

Um dieses Mapping mehrfach verwenden zu können und Namenskonflikte im selben Store zu vermeiden, erlauben die mapping-Attribute die Angabe von zusätzlichen Parametern: <cv-button class="round-button" mapping="tile-play-stop" progress-mapping="tile-play-progress('duration_key1')">

Dieser kann dann als Variable in der Formel benutzen werden:

<cv-mapping name="tile-play-progress">
    <formula>
        d = store.get(params[0]);
        y = d > 0 ? Math.round(100/d*x) : 0;
    </formula>
</cv-mapping>

params[0] enthält in dem Fall den Wert duration_key1. Die params Variable ist den den Formeln immer als Array vorhanden und leer, wenn keine angeben wurden.

Beispiel-Mappings

Hinweis

bei copy&paste einen UTF-8 fähigen Editor nutzen!

Wind und Windstärke

Für Wetterdaten in km/h:

<cv-mapping name="kmh2bft">
    <entry range-min="0" range-max="2">0</entry>
    <entry range-min="2" range-max="5">1</entry>
    <entry range-min="5" range-max="11">2</entry>
    <entry range-min="11" range-max="19">3</entry>
    <entry range-min="19" range-max="28">4</entry>
    <entry range-min="28" range-max="38">5</entry>
    <entry range-min="38" range-max="49">6</entry>
    <entry range-min="49" range-max="61">7</entry>
    <entry range-min="61" range-max="74">8</entry>
    <entry range-min="74" range-max="88">9</entry>
    <entry range-min="88" range-max="102">10</entry>
    <entry range-min="102" range-max="117">11</entry>
    <entry range-min="117" range-max="1e99">12</entry>
</cv-mapping>

<cv-mapping name="kmh2wind_text">
    <entry range-min="0" range-max="2">Windstille</entry>
    <entry range-min="2" range-max="5">leiser Zug</entry>
    <entry range-min="5" range-max="11">leichte Brise</entry>
    <entry range-min="11" range-max="19">schwache Brise</entry>
    <entry range-min="19" range-max="28">maessige Brise</entry>
    <entry range-min="28" range-max="38">frische Brise</entry>
    <entry range-min="38" range-max="49">starker Wind</entry>
    <entry range-min="49" range-max="61">steifer Wind</entry>
    <entry range-min="61" range-max="74">stuermischer Wind</entry>
    <entry range-min="74" range-max="88">Sturm</entry>
    <entry range-min="88" range-max="102">schwerer Sturm</entry>
    <entry range-min="102" range-max="117">orkanartiker Sturm</entry>
    <entry range-min="117" range-max="1e99">Orkan</entry>
</cv-mapping>

Für Wetterdaten in m/s:

<cv-mapping name="ms2bft">
    <entry range-min="0" range-max="0.3">0</entry>
    <entry range-min="0.3" range-max="1.6">1</entry>
    <entry range-min="1.6" range-max="3.4">2</entry>
    <entry range-min="3.4" range-max="5.5">3</entry>
    <entry range-min="5.5" range-max="8.0">4</entry>
    <entry range-min="8.0" range-max="10.8">5</entry>
    <entry range-min="10.8" range-max="13.9">6</entry>
    <entry range-min="13.9" range-max="17.2">7</entry>
    <entry range-min="17.2" range-max="20.8">8</entry>
    <entry range-min="20.8" range-max="24.5">9</entry>
    <entry range-min="24.5" range-max="28.5">10</entry>
    <entry range-min="28.5" range-max="32.7">11</entry>
    <entry range-min="32.7" range-max="1e99">12</entry>
</cv-mapping>

<cv-mapping name="ms2wind_text">
    <entry range-min="0" range-max="0.3">Windstille</entry>
    <entry range-min="0.3" range-max="1.6">leiser Zug</entry>
    <entry range-min="1.6" range-max="3.4">leichte Brise</entry>
    <entry range-min="3.4" range-max="5.5">schwache Brise</entry>
    <entry range-min="5.5" range-max="8.0">maessige Brise</entry>
    <entry range-min="8.0" range-max="10.8">frische Brise</entry>
    <entry range-min="10.8" range-max="13.9">starker Wind</entry>
    <entry range-min="13.9" range-max="17.2">steifer Wind</entry>
    <entry range-min="17.2" range-max="20.8">stuermischer Wind</entry>
    <entry range-min="20.8" range-max="24.5">Sturm</entry>
    <entry range-min="24.5" range-max="28.5">schwerer Sturm</entry>
    <entry range-min="28.5" range-max="32.7">orkanartiger Sturm</entry>
    <entry range-min="32.7" range-max="1e99">Orkan</entry>
</cv-mapping>

<cv-mapping name="ms2wind_fulltext">
    <entry range-min="0" range-max="0.2">Windstille - Keine Luftbewegung. Rauch steigt senkrecht empor</entry>
    <entry range-min="0.2" range-max="1.5">Geringer Wind - Kaum merklich. Rauch treibt leicht ab</entry>
    <entry range-min="1.5" range-max="3.3">Leichter Wind - Blätter rascheln. Wind im Gesicht spürbar</entry>
    <entry range-min="3.3" range-max="5.4">Schwacher Wind - Blätter und dünne Zweige bewegen sich, Wimpel werden gestreckt </entry>
    <entry range-min="5.4" range-max="7.9">Mäßiger Wind - Zweige bewegen sich, loses Papier wird vom Boden gehoben</entry>
    <entry range-min="7.9" range-max="10.9">Frischer Wind - Größere Zweige und Bäume bewegen sich, Wind deutlich hörbar </entry>
    <entry range-min="10.9" range-max="13.8">Starker Wind - Dicke Äste bewegen sich, hörbares Pfeifen an Drahtseilen, in Telefonleitungen</entry>
    <entry range-min="13.8" range-max="17.1">Steifer Wind - Bäume schwanken, Widerstand beim Gehen gegen den Wind</entry>
    <entry range-min="17.1" range-max="20.7">Stürmischer Wind - Große Bäume werden bewegt, Fensterläden werden geöffnet, Zweige brechen von Bäumen, beim Gehen erhebliche Behinderung</entry>
    <entry range-min="20.7" range-max="24.4">Sturm - Äste brechen, kleiner Schäden an Häusern, Ziegel und Rauchhauben werden von Dächern gehoben, Gartenmöbel werden umgeworfen und verweht, beim Gehen erhebliche Behinderung</entry>
    <entry range-min="24.4" range-max="28.4">schwerer Sturm - Bäume werden entwurzelt, Baumstämme brechen, Gartenmöbel werden weggeweht, größere Schäden an Häusern; selten im Landesinneren</entry>
    <entry range-min="28.4" range-max="32.6">orkanartiker Sturm - heftige Böen, schwere Sturmschäden, schwere Schäden an Wäldern (Windbruch), Dächer werden abgedeckt, Autos werden aus der Spur geworfen, dicke Mauern werden beschädigt, Gehen ist unmöglich; sehr selten im Landesinneren</entry>
    <entry range-min="32.6" range-max="1e99">Orkan - Schwerste Sturmschäden und Verwüstungen; sehr selten im Landesinneren</entry>
</cv-mapping>

Windrichtung

<cv-mapping name="Windrichtung_°">
    <entry range-min="0" range-max="11.25">Nord</entry>
    <entry range-min="11.25" range-max="33.75">Nordnordost</entry>
    <entry range-min="33.75" range-max="56.25">Nordost</entry>
    <entry range-min="56.25" range-max="78.75">Ostnordost</entry>
    <entry range-min="78.75" range-max="101.25">Ost</entry>
    <entry range-min="101.25" range-max="123.75">Ostsüdost</entry>
    <entry range-min="123.75" range-max="146.25">Südost</entry>
    <entry range-min="146.25" range-max="168.75">Südsüdost</entry>
    <entry range-min="168.75" range-max="191.25">Süd</entry>
    <entry range-min="191.25" range-max="213.75">Südsüdwest</entry>
    <entry range-min="213.75" range-max="236.25">Südwest</entry>
    <entry range-min="236.25" range-max="258.75">Westsüdwest</entry>
    <entry range-min="258.75" range-max="281.25">West</entry>
    <entry range-min="281.25" range-max="303.75">Westnordwest</entry>
    <entry range-min="303.75" range-max="326.25">Nordwest</entry>
    <entry range-min="326.25" range-max="348.75">Nordnordwest</entry>
    <entry range-min="348.75" range-max="360">Nord</entry>
</cv-mapping>