Seite 1 von 2

Volume Control mit langem Tastendruck

Verfasst: 14. Jan 2024 16:04
von Norick
Ich möchte über ein DSL SCript in OH4 mit einem langen Tastendruck die Lsautstärke verstellen. Ich habe dazu von Udo ein Script gefunden, dass ich ein wenig angepasst habe aber noch einen Fehler hat den ich nicht lösen kann.

Das Skript:

Code: Alles auswählen

var Timer tDim = null                                                                    

rule "VolumeDown"

when
    Item Audio__Bad_Bad_Rth_Taster_links_unten_Radio_VolDown received command 
then
    logDebug("Radio Volume","Rule VolumeDown triggered")
    
	if(tDim === null)                                                                					// only when there is no running timer
        logDebug("Radio Volume","timer was null")
		
        tDim = createTimer(now.plusMillis(100) [|                                    					// start timer fast
        logDebug("Radio Volume","dimmer timer executed")
        var Number nDim = 0                                                          					// helper var
		
        if(SqueezeBox_Player_Volume.state as Number) > 0) {        							 			// dimmer is not 100% 
            logDebug("Radio Volume","dimm up from {}%",SqueezeBox_Player_Volume.state)
            SqueezeBox_Player_Volume.sendCommand((SqueezeBox_Player_Volume.state as Number) - 1)        // dim down
            nDim = 1                                                                 					// set dim time to 1 Second
		}
		else {    
                logDebug("Radio Volume","Volume ist <= 0 {}%",SqueezeBox_Player_Volume.state)
                nDim = 1 
		}
		
        if(nDim > 0)                                                                 					// check of nDim was set
            logDebug("Radio Volume","reschedule timer with {} Second(s)",nDim)
            tDim.reschedule(now.plusSeconds(nDim))                                   					// nDim was set, so reschedule timer
        else                                                                         					// nDim wasn't set
            logDebug("Radio Volume","delete timer.")
            tDim = null                                                              					// so delete timer
        ])
end

Der Fehler:

Code: Alles auswählen

[INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'VolumeDown.rules'
[WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'VolumeDown.rules' has errors, therefore ignoring it: [17,54]: no viable alternative at input '>'
[17,57]: missing ']' at ')'
[22,3]: mismatched input 'else' expecting 'end'
KAnn mir bitte jemand helfen?

Re: Volume Control mit langem Tastendruck

Verfasst: 14. Jan 2024 19:11
von udo1toni
Fangen wir mal eine Stufe vorher an... Welche Art Tasten?
Zweite Frage... vor wievielen Jahren habe ich die entsprechende Rule gezeigt?
Dritte Frage (ich höre nicht auf...) Hast Du verstanden, wie die Rule funktioniert?

Zur Erläuterung...
Eigentlicher Auslöser des Fehlers sind eine fehlende öffnende runde Klammer in Zeile 18 (wenn var Timer tDim = null in Zeile 1 steht) und ein fehlendes Komma in Zeile 14. Die Rule wird aber so oder so nicht funktionieren, es fehlen noch weitere Klammern (geschwungene, Zeile 26, 29 und 32). Damit wird tDim immer genullt, nachdem der Timer einmal neu angelegt wurde (egal ob nDim 1 oder 0 ist)
Wenn Du die geschwungenen Klammern um die Codeblöcke von if und else ergänzt, wird es nicht besser, denn es gibt keine Stelle, an der der Timer abgebrochen wird - in der Schleife wird nDim definiert als 0, anschließend wird entweder nDim auf 1 gesetzt und die Lautstärke reduziert oder nDim auf 1 gesetzt und die Lautstärke nicht reduziert. Falls nDim nicht 0 ist, wird anschließend der Timer erneut ausgeführt. -> Endlosschleife.

Um mit langem Tastendruck zu arbeiten, brauchst Du unbedingt ein Signal, wenn die Taste gedrückt wird und ein Signal, wenn die Taste losgelassen wird. Im Zweifel sollten das zwei unterschiedliche Signale sein, die aber von der selben(!) Rule ausgewertet werden.

Unter openHAB4 (und auch schon unter openHAB3) gibt es kein .plusMillis() mehr. Der kurze Weg wäre .plusNanos() (eine Millisekunde sind eine Million Nanosekunden). Es gibt aber mit .plus(100, ChronoUnit.MILLIS) einen auch exakten Ersatz.

Die Verständnisfrage ergibt sich daraus, dass nDim als Zeitfaktor verwendet wird. Mutmaßlich habe ich die Frequenz damals konfigurierbar gemacht - aber es ist sicher nicht Dein Wunsch, 100 Sekunden die Taste halten zu müssen, um die Lautstärke von Maximum zu Minimum zu steuern.

Weiterhin gibt es in der Rule gar keinen Teil mit kurzem Tastendruck... Man sollte vermeiden, mehrere Rules mit identischem Trigger anzulegen :)

Re: Volume Control mit langem Tastendruck

Verfasst: 15. Jan 2024 06:58
von Norick
Ja gut ich habe einen Binärtaster (kein Schalter) welchen ich auswerten kann. Bei drücken geschlossen, loslassen offen. Ich kann aber nicht sagen wann und wo du diese rule gemacht hast ist wohl schon länger her ;)

Was ich aber verstanden habe ist, dass ich diese rule so nicht verwenden kann. In diesem Fall muss ich wieder auf Start zurück. Würdest du dies über eine dsl rule machen oder ist eine andere Sprache wie z.Bsp. Blockly besser geeignet? Ich würde am liebsten direkt alles über die UI machen aber ich bin mir nicht sicher ob dies so geht...

Re: Volume Control mit langem Tastendruck

Verfasst: 15. Jan 2024 12:06
von udo1toni
Die Sprachen sind (evtl. bis auf sehr spezielle Funktionen) vollständig für jedes Problem geeignet, es hängt also ausschließlich von Deinem Geschmack ab, wie Du Rules erstellst.
Allerdings: Wenn Du Dich mit JavaScript nicht auskennst, musst Du es erlernen, genau wie Ruby und die anderen Alternativen. Das gilt natürlich genauso auch für die DSL. Bei Blockly könnte man argumentieren, dass aufgrund des grafischen Ansatzes alles schön vorgegeben ist, ABER auch da gibt es diverse Dinge, die zumindest nicht auf den ersten Blick auffindbar sind, auch Blockly musst Du also erlernen. Hinzu kommt, dass Blockly mit einem Grundbefehlssatz kommt, der nicht mal alle Befehle beinhaltet, die die DSL mitbringt. Den fehlenden Teil muss man also selbst als Modul beisteuern - oder die passenden Module aus dem Marketplace nachinstallieren - auch da musst Du schon vorher wissen, dass es das betreffende Modul gibt...
Die DSL hat sehr einfache Schreibweisen, weil sie alle benötigten Module schon importiert hat. Du musst nicht auf eine ItemRegistry zugreifen, sondern schreibst einfach den Namen des Items hin, das ist in meinen Augen wesentlich einfacher zu verstehen.

Ruby ist wohl ähnlich klar, vielleicht sogar noch eine Ecke besser, nur kenne ich mich mit der DSL schon "ganz gut" aus, Ruby müsste ich hingegen erst erlernen, und auch Ruby ist als Sprache nicht vergänglich - die DSL ist hingegen noch bis einschließlich OH4 Teil des openHAB Core, sie soll zwar zukünftig genauso optional werden wie die anderen Script Sprachen, das wird aber frühestens mit OH5 passieren, also noch zwei Jahre Zeit ;) und selbst dann ist nur das Argument des unbedingten Vorhandenseins der Sprache hinfällig.

Für das Programmieren in Textform (egal welche Sprache) brauchst Du eine Befehlsreferenz, welche bei DSL denkbar kurz ausfällt, so kurz, dass sie leider bisher nicht gut dokumentiert ist. Dafür gibt es aber buchstäblich zehntausende schlechte und zumindest ein paar wirklich exzellente DSL Rules, verteilt über die diversen Foren, anhand derer man sich anschauen kann, welche Befehle es so gibt. (Deren korrekte Anwendung ist dann wieder ein Thema für sich, aber man kann ja fragen...)

Du kannst DSL Rules auch über die UI anlegen, das ist aber unpraktisch :) denn es gibt mit VS Code und dem dort verfügbaren openHAB Plugin einen Editor, der kaum Wünsche offen lässt (zumindest, wenn man Amateur ist). Er erkennt Fehler und zeigt diese an (die Fehlerprüfung geschieht dabei gegen das Live System, beinhaltet also auch Itemnamen und Datentypen, und auch dort steht (unzuverlässige) Code Completion zur Verfügung, heißt, man tippt den Anfang eines Wortes und bekommt die möglichen Ergänzungen angezeigt, die im Kontext sinnvoll sein könnten. Unzuverlässig heißt hier, es wird nicht immer alles angezeigt, das taugt also nicht als Befehlsreferenz, ist aber besser als nichts. Im Codefenster kannst Du auch den aktuellen Wert eines Items sehen (bei Group Items zusätzlich die Werte aller unmittelbaren Member), direkt im Code, das kann extrem hilfreich sein, wenn man in Rules auf bestimmte Status reagieren will.

Aber noch mal zurück zu Deinem Problem... Um was für einen Taster handelt es sich (welche Hardware)?
z.B. falls knx -> konfiguriere den Binäreingang auf zyklisches Senden solange gedrückt.
Falls Homematic oder Zigbee -> es sollte einen Channel geben, der Events ausgibt (Taster gedrückt, Taster losgelassen, Taster doppelt gedrückt usw.)
Falls Schnittstelle Marke Eigenbau -> baue das Modul so um, dass Du auch das Loslassen des Tasters gemeldet bekommst, also beim Drücken -> Item changed to ON, beim Loslassen -> Item changed to OFF.
Schon kann man sehr einfach auf kurz, lang, Doppelklick, Dreifachklick, Morsecode, whatever reagieren und jeweils unterschiedliche Dinge tun (mit Morsecode und Doppelklick... muss man sich aber klar machen, dass openHAB einen Befehl erst ausführen kann, wenn es erkannt hat, dass die Eingabe beendet ist - also z.B. nach dem kurzen Druck kein weiterer Tastendruck folgt).

Wenn der Event Bus Beginn und Ende des Tastendrucks liefert (oder alternativ auf andere Weise der lange Tastendruck erkannt werden kann) kommt die Rule dran.

Re: Volume Control mit langem Tastendruck

Verfasst: 15. Jan 2024 18:43
von Harka
udo1toni hat geschrieben: 15. Jan 2024 12:06 Bei Blockly könnte man argumentieren, dass aufgrund des grafischen Ansatzes alles schön vorgegeben ist, ABER auch da gibt es diverse Dinge, die zumindest nicht auf den ersten Blick auffindbar sind, auch Blockly musst Du also erlernen. Hinzu kommt, dass Blockly mit einem Grundbefehlssatz kommt, der nicht mal alle Befehle beinhaltet, die die DSL mitbringt. Den fehlenden Teil muss man also selbst als Modul beisteuern - oder die passenden Module aus dem Marketplace nachinstallieren - auch da musst Du schon vorher wissen, dass es das betreffende Modul gibt...
Moin,
da "muss" ich meinen Senf zu abgeben ;)
Auch für Blockly brauch es Grundkenntnisse im Programmieren (fast egal welche Sprache und wie viel Rost schon dran ist). Damit findet man die meisten Blöcke zügig und der Rest lernt sich schnell. Die Blöcke sind auch mit der Hilfe verlinkt und für Einsteiger können die Videos eine Hilfe sein. Falls mal ein spezieller Befehl nicht zur Verfügung steht, kann einfach der entsprechende Javascript-Befehl in Textform eingefügt werden. Die zusätzlichen Module sind nur bequemer und helfen, wenn man die Funktion öfters benötigt.

DSL-Rule und Blockly haben jeweils Vor- und Nachteile die sich beim Funktionsumfang imho aber leicht umschiffen lassen.

Ich habe mal ein Versuch gestartet die Aufgabe mit Blockly zu lösen. Ich gehe dabei davon aus das der Taster, so lange er gedrückt wird, auf ON ist. Der Lösungsvorschlag soll auch gleich noch für den Lauter-Taster gelten. Du kannst also bei einer Rule beide Taster als Trigger einsetzen. Kannst Du ja mal, so zum rein schnuppern, testen und ggf. an deine Bedürfnisse anpassen (bei Lautsprecher und Maximum auf jeden Fall deine Werte).
ForumVolumeBin1.png

Re: Volume Control mit langem Tastendruck

Verfasst: 15. Jan 2024 21:55
von udo1toni
Ja :) ich habe halt eine halbe Ewigkeit gebraucht, um dahinter zu kommen, wo ich den numericState herbekomme, denn für den state ohne numeric gibt es einen eigenen Block, weshalb ich lange gar nicht auf die Idee kam, dass der Block mit get "name" of Item hier der richtige ist.

Aber ich habe auch keinen Leidensdruck :) meine DSL funktioniert ja und ich kenne die Handvoll Standard Befehle plus diverse nicht ganz so triviale Dinge, warum sollte ich also anfangen grafisch zu programmieren...

Re: Volume Control mit langem Tastendruck

Verfasst: 15. Jan 2024 23:06
von Harka
Wenn ich mit Bordmitteln DSL programmieren will, muss ich auch erstmal wissen das es verschiedene Arten von State gibt. Ich hatte nur den Eindruck, das Blockly hier unnötig schlecht weg kam. Es ist für uns von der Amateurliga imho eine gutes Werkzeug um kleine bis mittlere Regeln zu erstellen. So manche Fehler, wie die hier falsch gesetzten Klammern, passieren einem damit gar nicht erst.

Wenn jetzt noch der Udo mit seinem Wissen und seiner Hilfsbereitschaft zu uns ins Blockly-Lager wechselt ... huch, ich träume schon. :lol:

Re: Volume Control mit langem Tastendruck

Verfasst: 16. Jan 2024 00:09
von udo1toni
Harka hat geschrieben: 15. Jan 2024 23:06 Ich hatte nur den Eindruck, das Blockly hier unnötig schlecht weg kam.
Das lag nicht in meiner Absicht :) (ehrlich!)

Es gibt in der DSL übrigens nur einen State (.state), nur kann ich den Status unterschiedlich betrachten, mal als "richtigen" Status (ON, OFF, OPEN, CLOSED...), mal als String ("ON", "OFF", "Konstantinopel", "Hurslibarsli"...), mal als Zahl (-3, 5.7, 42...), mal als einheitenbehaftete Zahl (228.7 V, 89 °F, 22 mm/h...), und da man den Status unterschiedlich verwendet, muss man im Zweifel den passenden Datentyp erzwingen.
Was geschieht eigentlich in Blockly, wenn man numericState aufruft, das Item aber gerade keinen numerischen Wert hält (z.B. NULL oder UNDEF)? In der DSL muss/sollte man das immer abfangen, sonst droht eine hässliche nullPointerException.

Re: Volume Control mit langem Tastendruck

Verfasst: 16. Jan 2024 05:38
von Harka
null
Bei meinem Lösungsvorschlag passiert - nichts. Bei der DSL-Rule oben fehlt dann aber auch noch was.
@Norick - achte auf solche möglichen Fehler und fange diese ab. Sonst wundere Dich zumindest nicht, wenn sie, z.B. nach einem Neustart, mal nicht wie gewohnt funktionieren.

E: das war heute Morgen nur zwischen Tür und Angel. Habe selbst damit keine nennenswerte Probleme weil die Persistence ein restore macht aber Udo hat recht. Ich würde vor dem Timer einfach noch einen Test einfügen und die Lautstärke im Fall der Fälle mit einen kleinen Wert initialisieren.
ForumVolumeBin2.png

Re: Volume Control mit langem Tastendruck

Verfasst: 16. Jan 2024 13:14
von udo1toni
:) Gut zu wissen. Es ging mir nicht darum, Blockly anzugreifen (das ging es noch nie). Es hat mich lediglich interessiert, wie sich Blockly hier verhält :)