Seite 2 von 2

Re: Rules: Triggern von nur einem Zustand innerhalb der ".map" Datei (IR Fernbedienung)

Verfasst: 5. Nov 2020 19:05
von Tomzk
Okey, die Ablaufsteuerung mit einer Zählervariablen ähnlich in dem Beispiel von Peter macht für mich Sinn.
Ich habe allerdings keine Rückmeldung der Geräte wenn ich die IR-Befehle sende, somit kann ich keine Bedingungen verwenden.

Würde ich dann trotzdem das .reschedule in meinem Falle nutzen?
Ich verstehe es so, dass ich reschedule nur nutze wenn ich innerhalb des Timers den Loop solange wiederholen möchte bis Bedingung x erfüllt ist (in meinem Fall habe ich ja keinen Bedingungen)

Mein Ziel ist es, die Steckdose bei triggern der Rule einzuschalten, 15 Sekunden warten bis ESP hochgefahren ist und per IR-Befehlt die Anlage anzuschalten. 5 Sekunden nach dem Anschalten der Anlage kann ich dann auf den korrekten Input der Anlage schalten.
Sprich ich will ein Thread:sleep innerhalb eines Thread:sleep benutzen, im besten falle mit dem selben Timer.

kann man den selben Timer hintereinande erstellen wie in meiner Rule hier?
Und wann müsste ich den Timer nullen? Immer bevor ich ihn neu anlege oder schickt es einmalig vor Ende der Rule?

Hab mir schon mehrere Design Patterns im Englischen Forum angeschaut aber ich glaube das hat mich jetzt noch mehr verwirrt :?

Code: Alles auswählen

var Timer tSzene_TV=null

rule "Szene TV"
when
    Item Szene_TV changed from OFF to ON                            // Schalter zum aktivieren der Szene
then
    WZ_TVLampe.sendCommand(ON)
    ShellyPlugS_7A35C0_Power.sendCommand(ON)                        //Fernseher

    tSzene_TV?.cancel                                               // Falls Timer läuft stoppen
    tSzene_TV = createTimer(now.plusSeconds (15))[|                 // Abwarten bis ESP hochgefahren ist
        IR_Control.sendCommand("IRSEND,NEC,0x400501FE,32")          // Logitech Z906 "Power" --> (ircodes.map)
            tSzene_TV = createTimer(now.plusSeconds (5))[|          // Abwarten bis Anlage an ist  
                IR_Control.sendCommand("IRSEND,NEC,0x400530CF,32")  // Logitech Z906 "Input 3/ TV" --> (ircodes.map)
            ]
        tSzene_TV = null                                            // Timer = 0
    ]
    tSzene_TV = createTimer(now.plusSeconds (5))[|                  // Ausschalten nach 5 Sekunden
        Szene_TV.sendCommand(OFF)                                   // Wiederausschalten des Szenenswitchs
        tSzene_TV = null                                            // Timer = 0
    ]
end

Re: Rules: Triggern von nur einem Zustand innerhalb der ".map" Datei (IR Fernbedienung)

Verfasst: 6. Nov 2020 13:48
von udo1toni
Wie gesagt, das ist Quatsch. Die von Dir gepostete Rule macht folgendes:
Lampe und Shelly werden eingeschaltet. Anschließend wird ein eventuell laufender Timer (auf welchen auch immer der Zeiger tSzene_TV gerade zeigt) abgebrochen.
Danach wird ein Timer erzeugt und dem Zeiger zugewiesen. Inhalt:

Code: Alles auswählen

IR_Control.sendCommand("IRSEND,NEC,0x400501FE,32")          // Logitech Z906 "Power" --> (ircodes.map)
            tSzene_TV = createTimer(now.plusSeconds (5))[|          // Abwarten bis Anlage an ist  
                IR_Control.sendCommand("IRSEND,NEC,0x400530CF,32")  // Logitech Z906 "Input 3/ TV" --> (ircodes.map)
            ]
        tSzene_TV = null
Unmittelbar daran anschließend(!)wird ein weiterer Timer erstellt, der dem selben Zeiger zugewiesen wird (womit es keinen gültigen Zeiger auf den ersten Timer mehr gibt). Inhalt des Timers:

Code: Alles auswählen

        Szene_TV.sendCommand(OFF)                                   // Wiederausschalten des Szenenswitchs
        tSzene_TV = null                                            // Timer = 0
Dieser Timer wird nach 5 Sekunden ausgeführt, das heißt, das Item Szene_TV bekommt den Befehl 0. Anschließend wird der Zeiger gelöscht.
Zehn Sekunden später läuft der Timer ab, auf welchen es keinen gültigen Zeiger gibt. Der Timer sendet den Befehl IRSEND,NEC,0x400501FE,32 an das Item IR_Control und definiert einen Timer, der nach 5 Sekunden abläuft. Inhalt:

Code: Alles auswählen

                IR_Control.sendCommand("IRSEND,NEC,0x400530CF,32")  // Logitech Z906 "Input 3/ TV" --> (ircodes.map)
Der Timer wird dem Zeiger zugewiesen, welcher unmittelbar darauf gelöscht wird.
Du möchtest eigentlich etwas komplett anderes haben:

Code: Alles auswählen

var Timer tSzene_TV = null
var Integer nSzene_TV = 0

rule "Szene TV"
when
    Item Szene_TV changed from OFF to ON                            // Schalter zum aktivieren der Szene
then
    tSzene_TV?.cancel                                               // Falls Timer läuft stoppen
    nSzene_TV=0
    tSzene_TV = createTimer(now, [|                                // Ablaufsteuerung
        nSzene_TV = nSzene_TV + 1
        switch(nSzene_TV) {
            case 1: {                                              // Schritt 1 (ohne Verzögerung)
                WZ_TVLampe.sendCommand(ON)
                ShellyPlugS_7A35C0_Power.sendCommand(ON)           // Fernseher
            }
            case 2: {                                              // Schritt 2 (nach 5 Sekunden)
                Szene_TV.postUpdate(OFF)                           // Wiederausschalten des Szenenswitchs
            }
            case 3: {}                                             // Schritt 3 (nach 10 Sekunden, nix tun)
            case 4: {                                              // Schritt 4 (nach 15 Sekunden)
                IR_Control.sendCommand("IRSEND,NEC,0x400501FE,32") // Logitech Z906 "Power" --> (ircodes.map)
            }
            case 5: {                                              // Schritt 5 (nach 20 Sekunden)
                IR_Control.sendCommand("IRSEND,NEC,0x400530CF,32") // Logitech Z906 "Input 3/ TV" --> (ircodes.map)
                tSzene_TV = null                                   // Zeiger auf Timer löschen
            }
        }
        if(tSzene_TV !== null)                                     // falls Zeiger nicht null
            tSzene_TV.reschedule(now.plusSeconds(5))               // Timer erneut in 5 Sekunden ausführen
    ])
end
Es geht dabei um Kontrolle. In dem Moment, wo Du einen Zeiger (tSzene_TV) auf null setzt, verlierst Du die Kontrolle über den Timer (der Timer ist denoch vorhanden und wird ausgeführt).
Der Ablauf ist hier in 5-Sekunden-Schritten organisiert. die Anweisung "case 3" habe ich hier nur der Vollständigkeit halber aufgeführt, die Zeile kann entfallen. Der Timer wird einfach ausgeführt und tut nichts weiter, als sich selbst neu zu planen.
Man könnte auch den reschedule pro case einsetzen, dann könnte man auf den "Leerschritt" verzichten, hätte dafür aber drei mal die fast identische Zeile im Code. Das sähe dann so aus:

Code: Alles auswählen

var Timer tSzene_TV = null
var Integer nSzene_TV = 0

rule "Szene TV"
when
    Item Szene_TV changed from OFF to ON                            // Schalter zum aktivieren der Szene
then
    tSzene_TV?.cancel                                               // Falls Timer läuft stoppen
    nSzene_TV=0
    tSzene_TV = createTimer(now, [|                                // Ablaufsteuerung
        nSzene_TV = nSzene_TV + 1
        switch(nSzene_TV) {
            case 1: {                                              // Schritt 1 (ohne Verzögerung)
                WZ_TVLampe.sendCommand(ON)
                ShellyPlugS_7A35C0_Power.sendCommand(ON)           // Fernseher
                tSzene_TV.reschedule(now.plusSeconds(5))           // Timer erneut in 5 Sekunden ausführen
            }
            case 2: {                                              // Schritt 2 (nach 5 Sekunden)
                Szene_TV.postUpdate(OFF)                           // Wiederausschalten des Szenenswitchs
                tSzene_TV.reschedule(now.plusSeconds(10))          // Timer erneut in 10 Sekunden ausführen
            }
            case 3: {                                              // Schritt 3 (nach 15 Sekunden)
                IR_Control.sendCommand("IRSEND,NEC,0x400501FE,32") // Logitech Z906 "Power" --> (ircodes.map)
                tSzene_TV.reschedule(now.plusSeconds(5))           // Timer erneut in 5 Sekunden ausführen
            }
            case 4: {                                              // Schritt 5 (nach 20 Sekunden)
                IR_Control.sendCommand("IRSEND,NEC,0x400530CF,32") // Logitech Z906 "Input 3/ TV" --> (ircodes.map)
                tSzene_TV = null                                   // Zeiger auf Timer löschen
            }
        }
    ])
end
Natürlich könnte man auch die unmittelbar auszuführenden Befehle vor dem Anlegen des Timers ausführen und den Timer 5 Sekunden in der Zukunft ausführen lassen. Die gezeigte Variante hat aber den Vorteil, dass der gesamte Ablauf im Timer liegt, man kann also klar erkennen, wie die Steuerung funktioniert.

Re: Rules: Triggern von nur einem Zustand innerhalb der ".map" Datei (IR Fernbedienung)

Verfasst: 8. Nov 2020 10:32
von Tomzk
Hallo Udo,

Danke für die Rule und die ausführliche Beschreibung meiner doch leicht verrückten Rule am Anfang. Dadurch ist mir einiges klar geworden.

Zu deiner Variante, ist es so das die „case“ Zahl dann immer automatisch den count in diesem Beispiel von nSzene_TV entspricht?
Ich hätte vor dem Post erwartet, das ich jedem case eine Bedingung zuweisen hätte müssen.
Sprich case 3 ist wenn nSzene_TV = 3 usw...

Danke und Gruß
Tom


Gesendet von iPhone mit Tapatalk

Re: Rules: Triggern von nur einem Zustand innerhalb der ".map" Datei (IR Fernbedienung)

Verfasst: 9. Nov 2020 09:18
von udo1toni
nSzene_TV wird ja beim Anlegen des Timers auf 0 gesetzt und dann zum Eintritt in den Timer jeweils hochgezählt.
Die Anweisung switch(nSzene_TV) ist der Schlüssel, der bei case als Vergleichsoperator verwendet wird. Deshalb reicht es, den Wert hinzuschreiben.


Gesendet von iPad mit Tapatalk