Item Werte in Rules auslesen

Allgemeine Fragen rund um die "Smart Home" Hardware/Komponenten

Moderatoren: seppy, udo1toni

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Item Werte in Rules auslesen

Beitrag von shuo »

Hallo zusammen, ich hätte mal eine - hoffentlich keine blöde - Frage. Kann mir jemand die Unterschiede in dem unten genannten Beispiel erklären?

Code: Alles auswählen

Number Item
In der Rule

Code: Alles auswählen

if (Item > 0)

oder 

if (Item.state > 0)

oder

if ((Item.state as Number) > 0)

oder 

if ((Item.state as Number).floatValue >0)
Vielen Dank vorab

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Item Werte in Rules auslesen

Beitrag von udo1toni »

Gerne.

Code: Alles auswählen

if(Item > 0) // Das ist Quatsch (bzw. wurde einfach das .state vergessen)

if(Item.state > 0) // Prüfe, ob der Status des Items größer 0 ist. Das kann funktionieren, sicher ist es aber nicht

if((Item.state as Number) > 0) // Prüfe, ob der Status des Items, als Nummer betrachtet, größer 0 ist

if((Item.state as Number).floatValue >0) // Prüfe, ob der Status des Items, als Nummer, die nach Float gewandelt wurde größer 0 ist
Bei einem reinen Number Item wird es gewöhnlich keinen Unterschied zwischen den drei letzten Tests geben, weil openHAB inzwischen relativ schlau ist und bei Bedarf das Casting nach Number (... as Number) automatisch erledigt. Das kann allerdings schief gehen.
Beim expliziten Casten nach Number (also das vorletzte Beispiel) wird sichergestellt, dass der Wert auch tatsächlich nach Number gecastst wird. Das hat aber einen Pferdefuß, denn ein Number Item kann mindestens noch die Status NULL und UNDEV halten (und beide Status können mittels postUpdate() auch erzwungen werden). In diesem Fall kann nicht nach Number gecastet werden, weil weder NULL noch UNDEV eine gültige Zahl darstellen. Deshalb kommt es im Anschluss zu einer NullPointerException, was hässlich ist. Also gehört vor solche expliziten Castings immer ein Test, ob es sich überhaupt um eine Zahl handelt:

Code: Alles auswählen

if(!(Item.state instanceof Number)) return; //Falls Status keine gültige Zahl enthält, brich die Rule ab.
Man kann natürlich auch anders als mit Abbruch reagieren, das ist nur eine tyspische Codezeile in dem Zusammenhang.

Die letzte Zeile (...floatValue) findet im Zusammenhang mit speziellen Number Items Anwendung, nämlich bei UoM Items. (Units of Measurement). Diese Items halten im Status nicht nur einen Zahlenwert sondern auch noch die passende Einheit, also z.B. 15.4 °C (und das wird dann auch so geloggt). Strenggenommen ist dieser Status dann vom Typ QuantityType, aber QuantityType basiert auf dem Typ Number, also sind sämtliche Measurements ebenfalls vom Typ Number. Und mehr noch, die Einheit bleibt auch erhalten, selbst wenn man den Wert in ein Objekt (Variable, Konstante) oder auch ein Primitive schreibt. Die Unit ist ziemlich hartnäckig und klebt fest. Bei einer Wandlung nach Integer (.intValue) oder Float (.floatValue) geht die Unit aber verloren. Wenn man in einer Rule mit dem Zahlenwert hantieren will, ist es oftmals die einfachste Variante, die Einheit wegzuzschmeißen. :)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Item Werte in Rules auslesen

Beitrag von shuo »

Super Udo, vielen Dank für die ausführliche Erklärung. Das erste ist natürlich mein copy paste Fehler gewesen....

Wo ich UoM Items verwenden könnte ist mir noch nicht ganz klar, denn die Einhat kann ich ja auch in der Beschreibung des Items definieren. Das heißt aber auch im Umkehrschluss das es - vorausgesetzt es gibt keine Einheit - es keinen Unterschied zwischen den letzten beiden gibt?

Nachtrag:

Noch eine Frage hab ich: Was ist denn dann der Unterschied bei folgenden Fällen? Wobei ich mir nicht sicher bin ob es den dritten überhaupt gibt?

Code: Alles auswählen

String item

Code: Alles auswählen

if(item.state == "bla")

if(item.state.toString == "bla")

if ((item.state instanceof String) == "bla" )

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Item Werte in Rules auslesen

Beitrag von udo1toni »

shuo hat geschrieben: 9. Dez 2021 08:11 Wo ich UoM Items verwenden könnte ist mir noch nicht ganz klar, denn die Einhat kann ich ja auch in der Beschreibung des Items definieren. Das heißt aber auch im Umkehrschluss das es - vorausgesetzt es gibt keine Einheit - es keinen Unterschied zwischen den letzten beiden gibt?
Der Punkt ist ein anderer. Stell Dir vor, Du hast ein Thermostat, welches die Temperatur in °F liefert. Die Channel sind UoM Channel. Dann wird ide Temperatur bei Dir in °C angezeigt. OHNE irgendetwas zu tun!!! Dein System ist nämlich auf SI-Einheiten konfiguriert, nicht auf imperiale Einheiten.
Umgekehrt funktioniert das genauso. Du kannst auch gezielt ein UoM Item auf eine bestimmte (passende...) Einheit konfigurieren, um z.B. den Wind im Beaufort anzuzeigen, oder in Knoten. (Wobei ich mir nicht sicher bin, ob diese Einheiten zur Verfügung stehen... aber es sollte klar sein, was ich meine ;) )
Genauso kannst Du auch in einer Rule mit Einheiten rechnen, Du kannst also z.B. 13°C + 4°F rechnen (ist natürlich auch wieder vollkommener Quatsch...)

UoM Items haben die Einheit, ohne dass sie explizit konfiguriert wird. bei normalen Items muss hingegen die Einheit extra angegeben werden, damit sie in der Anzeige erscheint.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Item Werte in Rules auslesen

Beitrag von shuo »

Verstanden. Vermutlich werde ich niemals damit in Berührung kommen. Meinst Du könntest mir noch Rückmeldug bezüglich den Strings geben?

Benutzeravatar
peter-pan
Beiträge: 2564
Registriert: 28. Nov 2018 12:03
Answers: 25
Wohnort: Schwäbisch Gmünd

Re: Item Werte in Rules auslesen

Beitrag von peter-pan »

shuo hat geschrieben: 9. Dez 2021 08:11 if ((item.state instanceof String) == "bla" )
Das gibt es nicht in DSL.
shuo hat geschrieben: 9. Dez 2021 08:11 if(item.state.toString == "bla")
Hier wandelst du erst einen x-beliebigen Typ (z.B. Number) in einen String-Typ um und vergleichst ihn dann mit einem String.
shuo hat geschrieben: 9. Dez 2021 08:11 if(item.state == "bla")
Das ist eigentlich der "normale" String-Vergleich

Hier ein Ausschnitt aus einer Test-Regel:

Code: Alles auswählen

    if (Season_Name.state instanceof Number){
      logInfo("Test instance", "Season_Name ist String: {}", Season_Name.state)
    }
    else {logInfo("Test instance", "Season_Name ist kein String: {}", Season_Name.state)}

    if (Moon_illumination.state.toString == "43.004910823431565"){
      logInfo("Test instance", "Season_Name ist {}", Moon_illumination.state)
    }
    else {logInfo("Test instance", "Season_Name ist nicht: {}", Moon_illumination.state)}

    if (Season_Name.state == "AUTUMN"){
      logInfo("Test instance", "Season_Name ist {}", Season_Name.state)
    }
    else {logInfo("Test instance", "Season_Name ist nicht: {}", Season_Name.state)}

und das/der Log dazu:

Code: Alles auswählen

2021-12-10 10:28:54.288 [INFO ] [nhab.core.model.script.Test instance] - Season_Name ist kein String: AUTUMN
2021-12-10 10:28:54.294 [INFO ] [nhab.core.model.script.Test instance] - Season_Name ist 43.004910823431565
2021-12-10 10:28:54.300 [INFO ] [nhab.core.model.script.Test instance] - Season_Name ist AUTUMN
Pi5/8GB(PiOS Lite 64-bit(bookworm)/SSD 120GB - OH4.1.1 openhabian

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Item Werte in Rules auslesen

Beitrag von udo1toni »

shuo hat geschrieben: 9. Dez 2021 16:33 Verstanden. Vermutlich werde ich niemals damit in Berührung kommen. Meinst Du könntest mir noch Rückmeldug bezüglich den Strings geben?
Ja, glatt überlesen... peter-pan hat's ja schon erläutert, aber der Vollständigkeit halber...

Ein Item ist in der DSL Rule ein Objekt. Objekte haben Eigenschaften und Methoden. .state z.B. ist eine Eigenschaft. Objekte erben ihre Methoden vom Parent. Das Ur-Objekt, also der Ausgangspunkt aller Objekte hat eine Methode .toString, welche genau das macht, sie erzeugt einen String. Da diese Methode direkt im root existiert, haben ausnahmslos alle Objekte diese Methode.

Im Unterschied dazu kann ein Status ein numerischer Wert sein oder auch nicht. Deshalb muss man dies zunächst prüfen (instanceof Number), bevor man eine Funktion verwendet, die zwingend einen numerischen Wert voraussetzt (as Number). Das as Number braucht es, um im entstehenden Objekt eine Eigenschaft .intValue und .floatValue nutzen zu können, denn diese sind nun mal nur für echte Zahlen definiert.

Entsprechend braucht es keine Prüfung instanceof String, weil .toString ja immer zur Verfügung steht. Es gibt auch kein as String, weil es ja die Methode gibt...

Ein Status ist erst mal nicht unbedingt ein String, sondern ein Status. Man kann jeden Status als String betrachten, muss das aber nicht zwingend tun:

Code: Alles auswählen

if(Item.state == OFF)             // hier wird der Status verwendet
if(Item.state.toString == "OFF")  // hier wird der Status zunächst in einen String gewandelt.
if(Item.state == "OFF")           // Das ist falsch. Kann funktionieren, muss aber nicht.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

shuo
Beiträge: 181
Registriert: 1. Sep 2018 18:24

Re: Item Werte in Rules auslesen

Beitrag von shuo »

Danke Udo und Peter-Pan für die Erläuterungen. Jetzt ist es mir klar!

rqxrqx
Beiträge: 32
Registriert: 8. Jun 2020 22:11

Re: Item Werte in Rules auslesen

Beitrag von rqxrqx »

Hallo Udo!

"Ein Item ist in der DSL Rule ein Objekt. Objekte haben Eigenschaften und Methoden. .state z.B. ist eine Eigenschaft. Objekte erben ihre Methoden vom Parent"
Gemäß meinen Verständnis müsste also mit "Item.state.flaotValue" eine Methode auf das Objekt item.state angewandt werden. Das funktioniert aber so nicht, auch wenn das item als number und nicht zB als number:temperture definiert ist. Man muss "(Item.state as Number).floatValue" schreiben.
Ich verwede das regelmäßig so, frage mich aber immer wie der "as Number" Teil zur Eigenschaften und Methoden Logik passt.
Ist der "as Number" Teil eine Methode oder Eigenschaft oder was anderes? Logisch wäre für mich eine Methode und die Syntax: ".toNumber" so wie es auch ".toString" gibt.
Wie gesagt meine Regeln mit as Number funktionieren, aber die Logikfrage stellt sich mir jedesmal und ich kann dazu nirgends eine Erklärung finden. Abgesehen davon verstehe ich nicht, warum man ein reines Number item überhaupt zu einer Number konvertieren muss. Klar das Number Item könnte auch NULL sein, aber da hilft die as Number Konveriterung auch nicht!
Vielleicht kanns du da Licht in die für mich unlogische Syntax bringen.

Danke Reinhard

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Item Werte in Rules auslesen

Beitrag von udo1toni »

Ein .state ist ein .state.
.state kann diverse unterschiedliche Datentypen enthalten, das ist zu dem Zeitpunkt der Programmierung nicht festgelegt.
Deshalb stehen auch keine entsprechenden Funktionen zur Verfügung, bis der Datentyp festgelegt ist.
Also muss .state nach Number gecastet werden (das heißt, .state soll als Number Typ betrachtet und so verwendet werden), denn für den Datentyp Number gibt es eine Funktion .floatValue.

.toString ist eine Methode, die für das root Objekt definiert ist. Das heißt, alle Objekte, die von diesem Ursprungsobjekt abgeleitet sind (also alle Objekte...) kennen diese Methode. Hätte man einen String, so müsste man eine Funktion nutzen, um aus dem String eine Zahl zu machen, das wäre dann .parse. Nun gibt es aber viele verschiedene Zahlen, Integer, Float, Double, BigInteger, hex, Binary, ... Und nicht immer ist der gewünschte Datentyp eindeutig am String festzumachen. Auch gibt es Strings, die nicht in eine Zahl gewandelt werden können.
Deshalb gibt es keine Methode .toNumber für Strings, sondern nur externe Funktionen, Float::parseFloat(String) bestimmt z.B. das Float Zahlenäquivalent zum übergebenen String. Wenn der String keine Zahl enthält, kümmert sich die Bibliothek um entsprechendes Fehlermanagement.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten