Langer Tastendruck mit KNX Binäreingang

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Hallo
ich habe ein KNX Binäreingang von Hager (TS302) welches aber nur einen kurzen Tastendruck erlaubt. Nun habe ich das Problem dass ich für einen Eingang auch einen langen Tastendruck verwenden möchte. Ich denke dies sollte mit OH3 auf irgendeine Weise mit einem Skript wahrscheinlich funktionieren.

Kann mir hierzu jemand weiterhelfen wie ich das Programmieren kann? :shock:

Besten Dank
von udo1toni » 2. Feb 2024 20:38
Das Problem ist eher, dass da kein OFF kommt.
Du musst den Schalter so parametrieren, dass er sowohl beim Drücken als auch beim Loslassen einmal sendet, am besten beim Drücken ein ON und beim Loslassen ein OFF.
Gehe zur vollständigen Antwort

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

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von udo1toni »

Sagen wir mal so: Wen Du Zugriff auf die Konfiguration per ETS hast, kannst Du im Zusammenspiel mit openHAB so gut wie alles realisieren :)

In diesem Fall wäre der einfachste Weg, den Binäreingang so zu konfigurieren, dass er beim Schließen des Kontakts eine 1 (ON) sendet und beim Öffnen eine 0 (OFF). Nun kannst Du in openHAB eine Rule erstellen, welche die Zeit zwischen ON und OFF ermittelt.
Auf diese Weise kannst Du auch Doppel- und Dreifach-Tastendruck erkennen, oder notfalls sogar Morse-Code :)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Nun Zugriff in der ETS habe ich - funktioniert. Kann ich dazu den OH Ruleeditor nehmen? Ich sehe für den "Trigger" keinen passenden Eintrag dazu um die Zeit zu ermitteln welche vom Tastendruck kommt. Kannst du mir bitte einen Tip geben?

Die Idee dies so zu realisieren finde ich gut.

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

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von udo1toni »

Im knx Binding gibt es keine Trigger, nur Zustände. Deshalb musst Du den Zustand der Taste in einem Item speichern, indem Du das Item mit dem passenden Channel verknüpfst. Anschließend kannst Du im log prüfen, ob das Drücken der Taste und das Loslassen der Taste im log ankommt.
Es gibt hier zwei Möglichkeiten, das zu definieren, entweder als switch-channel oder als switch-control Channel. Der Unterschied: switch sendet changed Events nach openHAB, switch-control sendet command Events nach openHAB.
Da Du den Tastendruck als solches in einer Rule auswerten musst, spielt es hier keine Rolle, welche Variante Du nimmst, wichtig ist das nur, wenn Du Channel unterschiedlicher Bindings an das selbe Item binden willst, um z.B. eine Hue Lampe von einem knx Taster aus zu steuern.

Nehmen wir also an, Du nutzt switch Channel, dann heißt der Trigger changed. In einer klassischen DSL Rule sieht das so aus:

Code: Alles auswählen

// Globale Variablen müssen zuoberst definiert werden (vor der ersten Rule in der Datei)
var Timer tTaste = null

rule "Taste auswerten"
when
    Item meineKnxTaste changed
then
    tTaste?.cancel
    if(newState == ON) {
        tTaste = createTimer(now.plusNanos(400000000),[| // 400 Millisekunden
            // Befehl: langer Tastendruck erkannt
        ])
    } else {
        if(!(tTaste.hasTerminated)) {
            // Befehl: kurzer Tastendruck erkannt
        }
    }
end
Zunächst wird ein eventuell laufender Timer gestoppt. Das ? führt die Methode .cancel nur aus, wenn der Zeiger tTaste nicht null ist.
Dann prüft die Rule, welchen Zustand die Taste hat (ON oder OFF).
Bei ON muss der Timer gestartet werden. Anschließend ist die Rule zuende.
Bei OFF prüft die Rule, ob der Timer noch nicht fertig abgelaufen war (hasTerminated == false, bzw. NOT(hasTerminated == true)), das ! bedeutet NOT, da if() immer true oder false auswertet und hasTerminated praktischerweise true oder false liefert, kann man das so schön kurz schreiben.
Falls hasTerminated also false ist, wurde der Timercode noch nicht ausgeführt, womit ein kurzer Tastendruck erkannt wurde. Danach ist die Rule beendet.

Läuft der Timer jedoch ab, so wird der Code ausgeführt, der im Lambda angegeben ist (das ist der Teil zwischen [ und ]). Da wir keine weitere Unterscheidung brauchen, wird hier einfach der Code ausgeführt, welcher bei einem langen Tastendruck ausgeführt werden soll.

Leider ist JavaTime übergenau, weshalb man die Zeitspanne in Nanosekunden angeben muss, also 400.000.000 Nanosekunden, bzw. 400.000 Microsekunden bzw. 400 Millisekunden. Wenn also der kurze Tastendruck allzu kurz sein muss, kannst Du diese Zahl entsprechend anpassen, z.B. auf 600.000.000 für 0,6 Sekunden. Die Zahl muss vom Typ Long sein, das ist hier automatisch der Fall, nur, falls man mit Variablen arbeiten will, müsste man das berücksichtigen...
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Danke für die Antwort..
Ich werde dies probieren so umzusetzen wie du geschrieben hast und melde mich dann nochmals ;)

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Nun ich habe die Rule bzw. den Zustand des Tasters in einem Item gespeichert. Da es noch nicht vollständig ist hätte ich kurz diese Fragen:

- Der Taster ist noch mit einer Lampe in der ETS verknüpft. Ist es korrekt dass ich diese Verbindung löschen muss wenn ich den langen Tasterdruck in OH verwenden möchte der eine andere Lampe schaltet?

Code: Alles auswählen

// Globale Variablen müssen zuoberst definiert werden (vor der ersten Rule in der Datei)
var Timer tTaste = null

rule "Taste auswerten"
when
    Item meineKnxTaste changed
then
    tTaste?.cancel
    if(newState == ON) {
        tTaste = createTimer(now.plusNanos(400000000),[| // 400 Millisekunden
            // Befehl: langer Tastendruck erkannt
        ])
    } else {
        if(!(tTaste.hasTerminated)) {
            // Befehl: kurzer Tastendruck erkannt
        }
    }
end
- Dort wo du schreibsst ""Befehl:...." Hier muss ich dann das Item reinschreiben welches für den Tastendruck ausgeführt wird - korrekt? Oder gibt es eine andere (einfachere) Möglichkeit eine Verknüpfung zwischen Rule und Item herzustellen?

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Hmmm schade dass dies niemand weiss...

Hier meine DSL-Rule:

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: TasterWohnen
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        var Timer tTaste = null rule "Taste auswerten" when
            Item TasterWohnen changed
        then
            tTaste?.cancel
            if(newState == ON) {
                tTaste = createTimer(now.plusNanos(400000000),[| // 400 Millisekunden
                    // Befehl: langer Tastendruck erkannt
                    logInfo("Taster WohnenSchlafen", "langer Tastendruck erkannt")
                    KNXDeviceAktorA3_WohnenLicht.sendCommand(ON)
                ])
            } else {
                if(!(tTaste.hasTerminated)) {
                    // Befehl: kurzer Tastendruck erkannt
                    logInfo("Taster WohnenSchlafen", "kurzer Tastendruck erkannt")
                    KNXDeviceAktorA3_KucheLicht.sendCommand(ON)
                }
            }
        end
    type: script.ScriptAction
dann bekomme ich mehrere Fehler im log:

Code: Alles auswählen

 1. The method or field rule is undefined; line 1, column 24, length 4
   2. The method or field when is undefined; line 1, column 47, length 4
   3. The method or field changed is undefined; line 2, column 111, length 7
   4. The method or field then is undefined; line 3, column 119, length 4
   5. The method or field end is undefined; line 18, column 704, length 3
   6. This expression is not allowed in this context, since it doesn't cause any side effects.; line 1, column 29, length 17
   7. This expression is not allowed in this context, since it doesn't cause any side effects.; line 2, column 56, length 4
   8. This expression is not allowed in this context, since it doesn't cause any side effects.; line 2, column 61, length 49
Hat jemand eine Idee wieso das so ist?

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

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von udo1toni »

Es ist ganz einfach. Die Rule, die ich Dir gezeigt habe, ist in einer Textdatei zu verwenden, im Ordner $OPENHAB_CONF/rules/, und die Datei muss die Endung .rules aufweisen. Wenn Du die Rule über die UI verwenden willst, geht das gewöhnlich auch (hier aber nicht), dann musst Du den gesamten Rahmen der Rule entfernen, weil die UI den Rahmen bereitstellt. Der Rahmen ist dies hier:

Code: Alles auswählen

rule "Name der Rule"
when
   // irgendwelche Trigger
then
    // hier steht der Code
end
Alles (außer die Zeile // hier steht der Code) ist der Rahmen der Rule und darf nicht im Codeblock in der UI eingegeben werden. Nicht das Wort rule, nicht das Wort when, nicht das Wort then, nicht das Wort end.

Wie erwähnt, kannst Du diese Rule aber nicht über die UI anlegen, weil sie einen Timer verwendet und auf diesen auch zugreifen muss. Dazu ist die Rule auf eine globale (eigentlich dateiweite) Variable angewiesen, das ist aus der UI heraus nicht ohne weiteres möglich. 3.4.1 bringt dazu eine Funktion, die ich mir aber noch nicht näher angeschaut habe. In der vorliegenden Form muss die Rule zwingend über eine *.rules Datei angelegt werden.
Norick hat geschrieben: 20. Jan 2023 06:42 Dort wo du schreibsst ""Befehl:...." Hier muss ich dann das Item reinschreiben welches für den Tastendruck ausgeführt wird - korrekt?
Genau. Ich hatte irgendwie Deine Antwort verpasst.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Norick
Beiträge: 234
Registriert: 31. Jan 2022 06:35

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von Norick »

Ok fast am Ziel aber noch nicht ganz :?

Diese Rule steht mit der Endung .rules im Verzeichnis "C:\openhab\conf\rules"

Diese Rule sieht so aus:

Code: Alles auswählen

rule "TasterWohnenSchlafenEingang_TasterSchlafenEingang"

var Timer tTaste = null rule "Taste auswerten"

when
Item TasterWohnenSchlafenEingang_TasterSchlafenEingang changed

then
	tTaste?.cancel
	if(newState == ON) {
		tTaste = createTimer(now.plusNanos(400000000),[| // 400 Millisekunden
		// Befehl: langer Tastendruck erkannt
		logInfo("Taster WohnenSchlafen", "langer Tastendruck erkannt")
		KNXDeviceAktorA3_WohnenLichtEsstisch.sendCommand(ON)
	])
	} else {
	if(!(tTaste.hasTerminated)) {
		// Befehl: kurzer Tastendruck erkannt
		logInfo("Taster WohnenSchlafen", "kurzer Tastendruck erkannt")
		KNXDeviceAktorA3_KucheLichtKochinsel.sendCommand(ON)
	}
	}
	end

Dann müsste ich als nächstes doch mit der Openhab UI -> Rules eine neue Rule anlegen welches für meine Taste (dies ist der Trigger) dann das .rules files aufruft - richtig? Habe ich mal so angelegt und sieht so aus:

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: TasterWohnenSchlafenEingang_TasterSchlafenEingang
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        var Timer tTaste = null rule "Taste auswerten" when
            Item TasterWohnenSchlafenEingang_TasterSchlafenEingang changed
        then
            tTaste?.cancel
            if(newState == ON) {
                tTaste = createTimer(now.plusNanos(400000000),[| // 400 Millisekunden
                    // Befehl: langer Tastendruck erkannt
                    logInfo("Taster WohnenSchlafen", "langer Tastendruck erkannt")
                    KNXDeviceAktorA3_WohnenLichtEsstisch.sendCommand(ON)
                ])
            } else {
                if(!(tTaste.hasTerminated)) {
                    // Befehl: kurzer Tastendruck erkannt
                    logInfo("Taster WohnenSchlafen", "kurzer Tastendruck erkannt")
                    KNXDeviceAktorA3_KucheLichtKochinsel.sendCommand(ON)
                }
            }
        end
    type: script.ScriptAction

Ich denke dieser letzte Schritt ist u.U. nicht richtig... ?!

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

Re: Langer Tastendruck mit KNX Binäreingang

Beitrag von udo1toni »

Wie kommst Du darauf, dass die Rule so korrekt sein könnte?

Die Definition einer Rule per Textdatei hat einen exakt festgelegten Rahmen:

Code: Alles auswählen

rule "Name der Rule"
when
    <Trigger der Rule>
then
    <auszuführender Code>
end
Das heißt: zwischen den Schlüselworten rule und when steht exakt ein String, sobald dieser Leerzeichen und/oder
Sonderzeichen enthält muss der String in Anführungszeichen gesetzt werden.
Zwischen den Schlüsselworten when und then steht mindestens ein Trigger, es können beliebig viele Trigger, mit dem Schlüsselwort or getrennt, angegeben werden. Ein Trigger besteht aus dem Schlüsselwort, welches die Art des Triggers beschreibt, also z.B. Item für ein Item, welches den Trigger liefert, dann einer Eingrenzung z.B. auf das konkrete Item (z.B. MeinItem) und danach, welche Art Trigger auftreten muss, z.B. changed, received update oder received command, optional kann noch explizit der Wert genannt werden, also z.B.

Code: Alles auswählen

Item MeinItem changed from OFF to ON
Diese Trigger entsprechen zu 100% denen, die auch über die Main UI im "when" Teil der Rule gesetzt werden können (rate mal, warum der Bereich in der UI den Namen when trägt)
Zwischen den Schlüsselworten then und end steht der auszuführende Code, die beiden Schlüsselworte sind nicht Bestandteil des Codes.

Ein globale Variable muss zu Beginn der Datei definiert werden, nicht irgendwo wo es gerade mal passt.
Eine lokale Variable muss innerhalb des Codeblocks definiert werden, bevor sie verwendet wird, innerhalb oder oberhalb des Kontextes, in dem sie benötigt wird.

Code: Alles auswählen

// Dateikopf
var Timer tMeinTimer = null // globale Variable

rule "meine erste Rule"
when
...
then
...
end

var MeineVariable1 = iregendwas // nicht erlaubt! Globale Variablen müssen vor der ersten Rule in der Datei definiert werden!

rule "meine zweite Rule"
var MeineVariable2 = irgendwas // nicht erlaubt! hier darf gar nichts stehen (außer einem Kommentar)
when
var MeineVariable3 = irgenwas // nicht erlaubt! hier dürfen nur Trigger stehen!
then
var MeineVariable4 = 4 // lokal definierte Variable
if(true) {
var MeineVariable5 = 5
logInfo("test","MeineVariable5 = {}",MeineVariable5) // funktioniert super!
}
logInfo("test","MeineVariable5 = {}",MeineVariable5) // geht schief! die Variable ist in diesem Kontext nicht definiert!
end
Ich habe oben bewusst auf Einrückungen verzichtet, diese sind optional. Allerdings helfen sie bei der Lesbarkeit :) Hier sollte aber vor allem klar werden, wo Variablen definiert werden dürfen, und wo nicht.
Interessant ist noch die Variable MeineVariable5. Die Definition der Variablen erfolgt innerhalb des Kontextes von if(), nachdem dieser Kontext beendet wurde (also außerhalb der {}) ist die Variable nicht mehr definiert.
Steht hinter if kein Klammerpaar {}, so gehört nur der nächste Befehl zum Kontext.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten