Langer Tastendruck mit KNX Binäreingang
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Langer Tastendruck mit KNX Binäreingang
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?
Besten Dank
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?
Besten Dank
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 AntwortDu 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.
- udo1toni
- Beiträge: 13864
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Langer Tastendruck mit KNX Binäreingang
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
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
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Re: Langer Tastendruck mit KNX Binäreingang
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.
Die Idee dies so zu realisieren finde ich gut.
- udo1toni
- Beiträge: 13864
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Langer Tastendruck mit KNX Binäreingang
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:
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...
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
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
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Re: Langer Tastendruck mit KNX Binäreingang
Danke für die Antwort..
Ich werde dies probieren so umzusetzen wie du geschrieben hast und melde mich dann nochmals
Ich werde dies probieren so umzusetzen wie du geschrieben hast und melde mich dann nochmals
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Re: Langer Tastendruck mit KNX Binäreingang
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?
- 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?
- 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
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Re: Langer Tastendruck mit KNX Binäreingang
Hmmm schade dass dies niemand weiss...
Hier meine DSL-Rule:
dann bekomme ich mehrere Fehler im log:
Hat jemand eine Idee wieso das so ist?
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
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
- udo1toni
- Beiträge: 13864
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Langer Tastendruck mit KNX Binäreingang
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:
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.
Code: Alles auswählen
rule "Name der Rule"
when
// irgendwelche Trigger
then
// hier steht der Code
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.
Genau. Ich hatte irgendwie Deine Antwort verpasst.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 234
- Registriert: 31. Jan 2022 06:35
Re: Langer Tastendruck mit KNX Binäreingang
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:
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:
Ich denke dieser letzte Schritt ist u.U. nicht richtig... ?!
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... ?!
- udo1toni
- Beiträge: 13864
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Langer Tastendruck mit KNX Binäreingang
Wie kommst Du darauf, dass die Rule so korrekt sein könnte?
Die Definition einer Rule per Textdatei hat einen exakt festgelegten Rahmen:
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.
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.
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.
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
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
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
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