Seite 1 von 1

Benutzerdefinierte Aktion erstellen

Verfasst: 10. Mai 2020 10:41
von alex200580
Guten Morgen,

ich benötige Hilfe bei folgendem Vorhaben:

Ich möchte aus verschiedenen .rules Dateien heraus eine Aktion starten können. Genauer gesagt sollen Durchsagen auf verschiedenen Abspielgeräten ausgeführt werden. Ich möchte in den .rules Dateien also eine Aktion wie z.B.

Durchsage('Wohnzimmer', 'Die Luftfeuchtigkeit ist zu hoch, bitte lüften!') verwenden.

(Analog zu z.B. sendTelegram("Bot","Text"); oder sendNotifiaction("User","Text")

mit dem ersten String gebe ich den Player an, mit dem zweiten den Durchsagetext. Mit der Aktion wird dann erst die Uhrzeit geprüft, (nächtliche Durchsagen sind nicht so cool), dann wird auf dem betreffenden Gerät ein Gong abgespielt, 2 Sekunden später dann der Text durchgesagt.
Aktuell führe ich das alles in den vielen Regeln separat durch. Um die Regeln zu vereinfachen und übersichtlicher zu gestallten möchte ich das mit der "benutzerdefinierten Aktion" lösen. Ich habe bereits versucht das mit einer Procedure zu lösen, ohne Erfolg. Auch ein Script kommt nicht in Frage, da man keine Argumente übergeben kann.

Hat jemand einen Lösungsansatz?

Ich verwende OH2.5.4 Release Build auf einem WIN 10 Rechner

Schon mal danke für eure Ideen,

Alex

Re: Benutzerdefinierte Aktion erstellen

Verfasst: 10. Mai 2020 13:13
von udo1toni
Du kannst dazu Lambdas verwenden. Das Lambda wird quasi wie eine globale Variable zu Beginn des Datei definiert: Schau mal hier:
https://community.openhab.org/t/reusabl ... otes/15888

Re: Benutzerdefinierte Aktion erstellen

Verfasst: 10. Mai 2020 13:48
von alex200580
Hallo,

mit Lambda habe ich es schon versucht:

Code: Alles auswählen

val Ansage= [ GenericItem strPlayer, GenericItem strAnsagetext |
    if ( strPlayer == "WZ") {
        if (Mute.state==OFF){
            playSound("chromecast:chromecast:GoogleHomeMiniWZ","Metal_Gong.mp3")
            createTimer(now.plusSeconds(2))[|
                say(""+strAnsagetext,"googletts:deDEStandardB" ,"chromecast:chromecast:GoogleHomeMiniWZ")
            ]
        }
    }
    if ( strPlayer == "Kalli") {
        if (Mute.state==OFF){
            playSound("chromecast:chromecast:GoogleHomeMiniKalli","Metal_Gong.mp3")
            createTimer(now.plusSeconds(2))[|
                say(""+strAnsagetext,"googletts:deDEStandardB" ,"chromecast:chromecast:GoogleHomeMiniKalli")
            ]
        }    
    }
    
]  
strPlayer und strAnsagetext habe ich als String-Items angelegt. Selbst wenn ich o.g. Code direkt in einer Regeldatei einfüge (Das möchte ich ja eigentlich nicht, sondern nur einmal angelegt) bekomme ich
{
"resource": "/t:/conf/rules/Sonoff_RF.rules",
"owner": "_generated_diagnostic_collection_name_#0",
"code": "org.eclipse.xtext.diagnostics.Diagnostic.Linking",
"severity": 8,
"message": "The method or field Ansage is undefined",
"startLineNumber": 53,
"startColumn": 13,
"endLineNumber": 53,
"endColumn": 19
}
Die Sonoff_RF.rules wertet eingehende RF-Codes aus und führt entsprechende Aktionen aus. Habe den Aufruf hier test weise auf einen Funktaster gelegt:

Code: Alles auswählen

if(RFBridge.state == '8B22B2')//3-fach Taster (2) Taste links
        {   logInfo("RULE","3-fach Taster 2 Taste links")
        
            Ansage.apply('WZ','Testdurchsage')
    }

Die Beispiele in deinem Link behandeln leider keine String Items die übergeben werden, keine Ahnung ob das so überhaupt funktionieren würde.

Gruß,
Alex

Re: Benutzerdefinierte Aktion erstellen

Verfasst: 10. Mai 2020 14:08
von alex200580
Update:

folgendes funktioniert:

Code: Alles auswählen

val Ansage= [ String strPlayer, String strAnsagetext |
    if ( strPlayer == "WZ") {
        if (Mute.state==OFF){
            playSound("chromecast:chromecast:GoogleHomeMiniWZ","Metal_Gong.mp3")
            createTimer(now.plusSeconds(2))[|
                say(""+strAnsagetext,"googletts:deDEStandardB" ,"chromecast:chromecast:GoogleHomeMiniWZ")
            ]
        }
    }
    if ( strPlayer == "Kalli") {
        if (Mute.state==OFF){
            playSound("chromecast:chromecast:GoogleHomeMiniKalli","Metal_Gong.mp3")
            createTimer(now.plusSeconds(2))[|
                say(""+strAnsagetext,"googletts:deDEStandardB" ,"chromecast:chromecast:GoogleHomeMiniKalli")
            ]
        }    
    }
    
]  
Wenn ich das oben in der Sonoff_RF.rules einfüge funktioniert der folgende Aufruf

Code: Alles auswählen

if(RFBridge.state == '8B22B2')//3-fach Taster (2) Taste links
        {   logInfo("RULE","3-fach Taster 2 Taste links")
        
            Ansage.apply('WZ','Testdurchsage')
    }
Allerdings müsste ich das dann ja in jeder meiner .rules Datei einfügen in der ich eine Sprachdurchsage programmiert habe. Genau das will ich ja nicht. Ist es nicht möglich die Lamda Definition einmal Global (für alle .rules Dateien) anzulegen und zu nutzen?

Gruß,
Alex

Re: Benutzerdefinierte Aktion erstellen

Verfasst: 10. Mai 2020 23:38
von udo1toni
Also das eine ist der Unterschied zwischen genericItem und String. das genericItem ist eben genau das: ein Item. Wenn Du ein Item übergibst, musst Du natürlich auch die Eigenschaft .name abfragen.

Das Andere ist der Wunsch, die Funktion dateiübergreifend zu verwenden. Vermutlich ist es dafür das Einfachste, eine Rule zu programmieren (und eben kein Lambda) und diese Rule gezielt zu triggern, nachdem Du die benötigten Parameter abgeladen hast. Es böte sich an, das über eine Gruppe zu erledigen.
Die Items:

Code: Alles auswählen

Group gAnsage
String ansage_Kalli (gAnsage)
String ansage_WZ (gAnsage)
Ein Label brauchen wir hier nicht, denn die Items müssen nirgendwo angezeigt werden.
Eine Rule:

Code: Alles auswählen

// Globale Variablen zu Beginn der Datei definieren!
var Timer tPause = null
var String strTarget = ""
var String strText = ""

rule "Ansage mit Gong" 
when
    Member of gAnsage received update
then
    if(Mute.state==ON) return;
    
    strTarget = "chromecast:chromecast:GoogleHomeMini" + triggeringItem.name.split("_").get(1)
    strText = triggeringItem.state.toString
    playSound(strTarget,"Metal_Gong.mp3")
    tPause?.cancel
    tPause = createTimer(now.plusSeconds(2), [|
        say(""+strText ,"googletts:deDEStandardB" ,strTarget)
    ])
end
Nun benutzt Du einfach immer ein ansage_Kalli.postUpdate("Text") bzw. ansage_WZ.postUpdate("Text").
Die Rule triggert in beiden Fällen. Zuerst prüft die Rule, ob Mute ON ist. Ist das der Fall, beendet sich die Rule.
Anschließend füllt sie die Variable strTarget mit dem korrekten String.
Die letzten Zeichen entsprechen dabei dem Teil des Itemnamens nach dem _
In die globale Variable strText kommt der zu sprechende Text.
Nun spielt die Rule den Gong auf dem passenden Gerät aus und legt die Pause ein.
Sobald der Timer abgelaufen ist, folgt der say-Befehl auf das passende Device.
Wichtig ist hier natürlich, dass die beiden Strings vorher in globale Variablen gerettet werden, damit sie im Timer zur Verfügung stehen. Man könnte auch speichern, welches der Geräte eine Ansage machen soll und im Timercode entsprechend verzweigen, das ist aber umständlicher.

Es gibt natürlich auch einen Pferdefuß... Es darf immer nur eine Meldung auf einen Player ausgegeben werden, es müssen immer mindestens 2 Sekunden (und ein paar hundertstel) vergehen, bis der Nächste Player oder die nächste Meldung ausgegeben werden kann.
Wenn es eine solche Einschränkung nicht geben darf, wird die Rule wesentlich komplexer, da dann die Texte in ein globales Array gerettet werden müssen, welches für jeden Player einen Slot und einen Timer bereithält. Über dieses Array muss der Timer dann entscheiden, für welchen Slot er zuständig ist (das heißt, im Array muss auch ein Zeitstempel mit rein) um dann entsprechend auszuspielen. Der Aufwand wird erheblich sein, vermutlich ist es dann einfacher, für jeden Player eine einzelne Rule nach dem Schema zu erstellen. Vorteil: Der Timer weiß, welches Item er auslesen muss, man kann sich dann die globalen Strings ersparen. Nachteil: der Code sieht nicht mehr sehr effizient aus...

Re: Benutzerdefinierte Aktion erstellen

Verfasst: 11. Mai 2020 08:37
von alex200580
Guten Morgen,

vielen Dank für die Lösung. Das ist genau das, was ich brauche. Und so simpel... :shock:
Da habe ich vor lauter Bäumen den Wald nicht gesehen. :roll:

Es kommt nur äußerst selten vor das Ansagen gleichzeitig generiert werden, deshalb ist die Lösung so wie sie ist perfekt!

Ganz herzlichen Dank für deine Bemühungen,

Gruß,
Alex