Timer in IPS im Script aufziehen

Hallo Zusammen,
ich suche nun schon länger nach eine simplen Möglichkeit einen Timer in einem Skript aufzuziehen. Z.B. wird das Skript per Knopfdruck gestartet, schaltet etwas ein und nach einer Zeit, die in einer Variablen gesetzt ist, wieder aus, bzw. ruft dann eine Funktion (im gleichen Skript) auf, die etwas macht. Es gibt einige Infos zu diesem Thema im Forum, aber die Lösungen, die ich gefunden habe, erscheinen mir einfach zu umständlich. Ich habe folgendes Fragment gefunden, dass scheinbar die Basis ist:

<?php if($_IPS['SENDER'] == "TimerEvent") { IPS_SetScriptTimer($_IPS['SELF'], 0); } else { IPS_SetScriptTimer($_IPS['SELF'], $dauer); } ?>

Ich habe es ausprobiert und versuchsweise hinter ein Event gehängt, das an einer Variablen hängt und letztlich das Script aufruft. Das funktioniert.
Damit ist meiner Meinung nach der „Ablauf“ verstreut über Variablen, Events und Skripte.
Ich hoffe, ich habe das Prinzip einfach nicht verstanden.
Es muss doch eine Möglichkeit geben im Code, ohne den Umweg über die Konfiguration von Events und Variablen, das alles in einem Skript durch 3 simple Aufrufe zu machen?

Möglichkeiten, Events/Variablen etc. skriptgesteuert zu erzeugen habe ich auch gefunden (aber bisher nicht durchblickt) und automatisiert nur die manuellen Schritte. Macht es aber in meinen Augen nicht übersichtlicher.
Vielleicht gibt es ja ein Modul, was einem die mühselige Konfiguration über die Oberfläche abnimmt, dann wäre das eine Hilfe, solange es universell ist.
Wäre klasse, wenn jemand einen konstruktiven Hinweis hätte.

Ich verstehe glaube ich dein Problem nicht so recht. In dem Code-Schnipsel, den du gepostet hast, steckt doch im Prinzip schon alles drin, was du brauchst.

Mit IPS_SetScriptTimer($_IPS['SELF'], $dauer); startest du einen Skripttimer, mit IPS_SetScriptTimer($_IPS[‚SELF‘], 0); ` deaktivierst du ihn wieder und mit der Prüfung auf den Sender kannst du darauf reagieren, ob das Skript durch den Skript-Timer ausgeführt wurde oder durch einen anderen Auslöser.

Du kannst damit doch alles erreichen, was du beschrieben hast. Bei manueller Ausführung (Prüfung auf Sender) machst du etwas und startest anschließend den Timer, wurde das Skript über den Skripttimer gestartet (wieder Prüfung des Senders), machst du etwas anderes und deaktivierst den Timer anschließend wieder.

Du kannst die Prüfung natürlich noch etwas verfeinern, wenn du sicherstellen willst, dass wirklich nur auf einen Skripttimer und nicht auf einen beliebigen Timer geprüft wird.

Hallo Slummi,
Deine Frage zu meiner Frage zeigt mir, dass ich es tatsächlich nicht richtig verstanden habe.
Ich möchte kein Event definieren müssen, um diesen Timer dahinter zu hängen. Ich möchte im Skript selber den Timer aktiveren.

Wenn ich den Codeschnipsel ausführe, läuft es in den Else-Zweig, weil IPS_Sender XXX einen anderen Wert als TimerEvent hat. Woher kommt dann, wenn es abgelaufen ist, der Wert TimeEvent? Ist das eine feste Größe? Alle Beispiele fragen auf den String TimerEvent ab. Ich habe hier eine Anforderung, dabei ziehe ich 3-5 Timer in einem Script auf. Dann kommt ja scheinbar immer TimerEvent. Wie kann ich dann noch unterscheiden, welcher der Timer gerade abgelaufen ist und gestoppt werden muss? Und warum muss ich den Timer, wenn er abgelaufen ist überhaupt stoppen?
Ich bin vielleicht verdorben, da ich schon seit Jahren iobroker nutze. Da sind solche Konstruktionen Einzeiler, mit dem Ablauf eines Timers wird einfach eine Callback aufgerufen.
So eine Konstruktion versuche ich nun mit der Logik in IPS übereinander zu bringen

Scripttimer laufen im festen Intervall und somit müssen sie mit dem Intervall 0 deaktiviert werden, wenn du nur eine einmalige Ausführung haben willst.
Wie du das Script und somit den Timer Initial startest ist stark davon abhängig wie du es einsetzen willst.
Das geht auch z.b. in einem Aktions-Skript um ein Geräte ein, und nach Zeit X auszuschalten.
Die Werte von SENDER sind fix und in der Doku hier zu finden:

Michael

Hier mal noch ein Beispiel, wie du eindeutig prüfen kannst, ob das Skript durch den Skripttimer ausgeführt wurde (hatte ich mal an anderer Stelle gepostet.

<?php

// Wenn das Skript durch den ScriptTimer aufgerufen wurde, den ScriptTimer deaktivieren
if (@$_IPS['EVENT'] === @IPS_GetObjectIDByName('ScriptTimer', $_IPS['SELF'])) {
    IPS_SetScriptTimer($_IPS['SELF'], 0);
}

// Wenn das Skript nicht durch den ScriptTimer aufgerufen wurde, ScriptTimer aktivieren
else {
    IPS_SetScriptTimer($_IPS['SELF'], 60);
}

Du musst da kein extra Event definieren. Das wird durch den Befehl erstellt.

Hallo zusammen,
erst mal vielen Dank für die schnelle Hilfe. Eine Frage zum Verständnis.
@ Nall-chan.
Du sagst, ScriptTimer laufen im festen Intervall.
Festes Intervall bedeutet, der Timer wird sofort wieder gestartet, wenn er abgelaufen ist. Also einmal eingestellt, läuft er ewig?
Wo kann man solche Details nachlesen? Die sind doch wichtig, aber obwohl ich die Doku schon an diversen Stellen durchforstet habe, bin ich auf solche Infos noch nicht unbedingt gestoßen.
@Slummi
Wenn das Skript durch den ScriptTimer aufgerufen wurde, den ScriptTimer deaktivieren…
Das ist ja genau mein Verständnisproblem. Das Script mit dem Timer wird ja nicht durch ein Script mit einem Timer aufgerufen, sondern im Script selber will ich X Timer starten, die lediglich Unterfunktionen abarbeiten. Deine Info klingt aber so, dass ich ein Skript mit den Timern anlegen müsste und dann in den Timern selber die Abarbeitung, die dann wieder in anderen Skripten steckt ?

Ziel ist z.B. eine Klasse TestTimer anzulegen, die eine Methode hat, um einen Timer zu erstellen und dann eine Methode in der abgeleiteten Klasse mit der eigentlichen Implementierung der Fachlichkeit aufruft. Dann müsste im Skript in dem ich das eigentliche Objekt erzeuge und darauf dann die Methode setTimer aufrufe, auch irgendwie das Ende des Timers erkannt werden… Ich bezweifle, dass das funktioniert.

Ich versuche das mal zu bauen um zu klären, was geht und was nicht.

Genau. Einmal gestartet, wird das Skript im vorgegebenen Intervall immer wieder ausgeführt, bis du den Timer deaktivierst (auf 0 setzt).

Nein, du kannst das alles im selben Skript tun. Du musst nur im Skript prüfen, wodurch es aufgerufen wurde (Variablenänderung, Timer, WebFront, manuell etc.) und in Abhängigkeit davon Funktionen ausführen oder nicht.

Du kannst pro Skript aber nur einen Skripttimer haben. Das ist eine spezielle Form eines zeitgesteuertes Ereignis. Brauchst du mehrere Timer mit unterschiedlichen Intervallen, musst du entsprechend viele zeitgesteuerte Ereignisse erstellen und dann entsprechend darauf prüfen. Schau dir dazu am besten mal die Doku zu den Ereignissen an. Das kannst du aber auch alles aus einem Skript tun oder auch manuell, wie du magst.

Ja, das war damit gemeint.

Na da wo auch der Befehl steht.

@mikel
Benutz doch den Ablaufplan.
Oder:

Warum so kompliziert?
Lass doch jeden Script mit seiner fachlichkeit sein eigenen scripttimer benutzen.

Starten kannst du die Timer dann indem du z.b. mit RunScript aus einem Hauptscript diese einzelnen aufrufst.

Michael

Hallo Michael,
das ist ja genau das Thema ich brauche in einem Skript 3 Timer, die sehr kurze Abstände prüfen 2-3 sek. Funktioniert seit Jahren mit einer anderen Plattform so einwandfrei. Und bei IPS muss ich das eine, saubere Skript, was genau eine Funktion erfüllt, zerhacken und auf mehrere Skripte aufteilen.

Der Ablaufplan ist schon ganz nett, und ich habe ihn an manchen Stellen eingesetzt, aber auch da ist das Konstrukt deutlich unübersichtlicher als meine 30 Zeilen Code, sauber kommentiert. Beim Ablaufplan ist auch ein Teil im Plan, ein anderer Teil in den Skripten, also alles schön verteilt.
Kann ich mich tatsächlich nicht mit anfreunden.

Aber eine Frage zum Schluss, weil ich schon wieder gescheitert bin.
Bei meinen neuen Versuchen habe ich es geschafft ein zyklisches Event mit einem Intervall von 30 sek zu erzeugen IPS_SetEventCyclic($eventId , 2 , 1 , 0 , 0 , 1 , 30) etc.
Funktioniert einwandfrei.

Dann habe ich versucht ein einmaliges Ereignis mit
IPS_SetEventCyclic($eventId , 1/Datumstyp/ , 0/Datumsintervall/ , 0/Datumstage/ , 0 /Datumstagesintervall/ , 0 /Zeittyp/ ,0 /Zeitintervall/ );

und mit DateFrom und TimeFrom und dem heutigen Datums und einer Zeit 30sec in der Zukunft anzugeben, in der Hoffnung, dass dann genau in 30 sec ein einmaliges Ereignis ausgelöst wird. Leider passiert gar nichts.
Ich habe nun fast alle Permutationen an Einstellungen durchprobiert, alle ohne Erfolg. Und die Doku gibt leider kein Beispiel für ein einmaliges Ereignis her.

Warum?
Ein Timer reicht dann doch.
Was willst du eigentlich erreichen?
Man kann auch im Script kurze Verzögerung einbauen oder das Script nacheinander X Funktionen ausführen lassen.

Es sind nie einmalige Ereignisse, es sind immer zyklische.
Du kannst aber mit IPS_SetEventCyclicDateTo (nicht From) das Ende festlegen. Was nicht heißt das es innerhalb From/To nicht häufiger feuern kann, wenn der Intervall entsprechend klein ist.

Vielleicht beschreibst du etwas detaillierter und nicht abstrakt was du eigentlich genau erreichen willst. Eventuell ist es ja viel einfacher als gedacht.
Michael

Ich bedanke mich auf jeden fall für Eure Geduld.
Wie gesagt, nutze ich seit Jahren ioBroker und da sind viele Dinge sehr einfach und intuitiv. Aufgrund der guten Kritiken habe ich mir dann vor einigen Monaten IPS und IPSStudio gekauft und habe auch ein paar der simplen Scripte aus iobroker mit Ablaufplänen nachbilden können. Ich lebe davon, Software zu schreiben, mache also tagtäglich nichts anderes und bin im Normalfall mit ein paar Codezeilen schneller als irgendwas zusammen zu klicken… Den Zustand habe ich bei IPS noch lange nicht erreicht. Da ich also mein Hobby zum Beruf gemacht habe, möchte ich auch in meiner Freizeit Spaß beim Programmieren haben und die Dinge verstehen, also ist das Zusammenklicken nicht meine Welt und langweilt mich eher… Wobei mich das Programmieren unter IPS bisher nicht erfreut… Ich würde sagen IPS ist wie SPS-Programmierung, die habe ich vor 20 Jahren verlassen, weil es mir einfach nie Spaß gemacht hat und im Gegensatz zu Hochsprachen vieles nicht möglich , oder mühsam ist.
Egal…
… Es gibt keine Einmaligen Ereignisse? Aber wie ist dann die Doku zu Verstehen, in der eindeutig DatumsTyp 1= Einmalig beschrieben wird. Was würde man dann damit erreichen können. ich dachte ja, ich erkenne die Funktion in einem Beispiel, was ich mir baue, aber dem war ja nicht so ?

Zu meinem simplen Problem, was ich auch mit einem Ablaufplan hin bekommen habe, aber lieber mit einem Skript lösen möchte:
Bewegungsmelder meldet Event, Licht wird eingeschaltet, Timer wird aufgezogen (20sec), nach Ablauf wird Licht wieder ausgeschaltet. Wenn während der Laufzeit des Timers wieder eine Bewegung registriert, gleichen Timer neu aufziehen, d.h. solange man sich bewegt, geht das Licht nicht aus. Klassisches Verfahren würde ich sagen.
Jetzt kommt der zweite Timer ins Spiel: Wenn man beim Verlassen des Raums den Lichtschalter (im Raum)bedient, dann Licht sofort ausschalten und zweiten Timer aufziehen, der das Event des Bewegungsmelders für 1-2 Sek unterdrücken, damit beim Rausgehen nicht sofort wieder eingeschaltet wird. 1 Event vom Bus, 2 Timer, 2 Callbacks (Licht An, LichtAus) 20 Zeilen Code, fertig.

Warum prüfst du nicht einfach in deinem Skript vorm Einschalten des Lichts, ob es in den letzten x Sekunden ausgeschaltet wurde? Wenn das der Fall ist, schaltest du es halt nicht (wieder) ein und deaktivierst stattdessen den Skripttimer.

Hallo Slummi,
Dein Vorschlag klingt wie eine gute Idee. Werde ich ausprobieren.
Nur um das im Kopf richtig zu verstehen:
Ich hänge mein Skript hinter das Event Präsenz und im Skript ziehe ich einen Timer auf, der im System als Objekt außerhalb (unterhalb) des Skriptes eingehängt wird.
Und dann, wenn er abgelaufen ist, ruft er das Skript selbst wieder auf um dort ggf. abgefangen zu werden ( if($_IPS[‚SENDER‘] == „TimerEvent“)). Dann kann ich ihn deaktivieren oder eben nicht.

Jetzt muss ich das gleiche Skript noch hinter das zweite Event (Schalter Aus betätigt) hängen,
und eine Variable timeOff setzt (aktuelle Zeit). Damit das Skript erkennt, dass es jetzt vom anderen Event aufgerufen wurde und nur dann die Variable timeOff setzt, , muss ich das prüfen.
Im Timer selber frage ich ab, ob timeOff < 2 sek. her ist und wenn ja, dann Timer deaktivieren und wenn nein, dann Licht wieder an und Timer laufen lassen.
Wenn er zurück kommt und timeOff >2 sek her, dann ist wohl keiner mehr im Raum und er kann sich sozusagen selbst deaktiveren und das Licht ausschalten.
Referenzieren kann ich ihn, so wie Du schon beschrieben hast (@IPS_GetObjectIDByName(‚ScriptTimer‘, $_IPS[‚SELF‘]))), weil der Timer sozusagen unter dem Skript hängt (IPS[‚SELF‘]).

Frage zum Schluss: Kann man Skripte eigentlich auch per PHP an Events hängen, so dass ich das nicht im Objektbaum zusammenklicken muss?
Ich probiere das aus und geben eine Info, ob ich glücklich bin.

Im Prinzip ja. Du bildest deinen Präsenzstatus über eine Variable in IPS ab. Diese Variabe überwachst du mit einem ausgelösten Ereignis, welches dann dein Skript aufruft. Im Skript selbst startest du dann mit IPS_SetScriptTimer() deinen Timer und prüfst dann über geeignete Systemvariablen, wie z.B. $_IPS['SENDER'], ob dein Skript durch Änderung der Präsenz oder durch den Skripttimer aufgerufen wurde.
Ein weiteres ausgelöstes Ereignis für das Ausschalten würde ich persönlich gar nicht anlegen. Es genügt doch, wenn du im Skript selbst prüfst, wann sich die Variable für das Licht (Ausschalten) zuletzt geändert hat und das behandelst du dann einfach entsprechend im Skript. Ich gehe jetzt einfach mal davon aus, dass es nur zwei Quellen zum Ausschalten gibt (Skript / Bewegungsmelder und manuell). Da weißt du ja dann, wer der Auslöser war.

Wie gesagt, ich sehe hier nicht die Notwendigkeit für ein weiteres Ereignis.

Alles was du in der Konsole machst, kannst du prinzipiell auch über PHP tun. Die Befehlsrefernz hilft da ungemein: Ereignisverwaltung — IP-Symcon :: Automatisierungssoftware

Wenn du es so, wie von mir vorgeschlagen löst, brauchst du aber nur ein ausgelöstes Ereignis. Dies manuell zu erstellen ist wesentlich einfacher als das auch noch über ein Skript zu realisieren. Man kann Dinge auch „overengineeren“. Nur weil etwas geht, muss es nicht der beste Weg sein.
Um den Skripttimer musst du dich nicht weiter kümmern, der wird ja über IPS_SetScriptTimer() erstellt und weitere Ergeignisse hättest du dann nicht.

Ist aber nur so eine abstrakte Idee, ohne die Details deines Aufbaus jetzt exakt zu kennen.

Das Doku-Kapitel zu den Ereignissen kennst du? Ereignisse — IP-Symcon :: Automatisierungssoftware
Ich habe anhand deiner Fragestellungen manchmal das Gefühl, dass dir das Konzept und die Funktionsweise der unterschiedlichen Ereignisse noch nicht so ganz klar sind.

Gruß
Slummi

Hallo Slummi,
… Das Doku-Kapitel zu den Ereignissen kennst du? Ereignisse — IP-Symcon :: Automatisierungssoftware
Ich habe anhand deiner Fragestellungen manchmal das Gefühl, dass dir das Konzept und die Funktionsweise der unterschiedlichen Ereignisse noch nicht so ganz klar sind.Da hast Du allerdings Recht und auch Nicht. Natürlich kenne ich die Doku und haben ungefähr 50 Tabs im Browse auf um die unterschiedlichsten Dinge zu sehen.

Ich finde die Doku beschreibt leider im Grunde jeden Befehl einzeln, aber das gibt, wenn man Neuling ist meiner Meinung nach kein geschlossenes Bild, mit dem man „Was mache ich am besten Wie“ erkennen könnte. Die Doku sieht so aus, wie die Doku unserer Programmierer mit der der Kunde dann meist nichts anfangen kann, weil er die technischen Zusammenhänge nicht kennt. Das Programmiermodell von IPS ist gewöhnungsbedürftig würde ich sagen, aber vielleicht verstehe ich das irgendwann auch.

Ich wollte schon mehrfach die ganze Klamotte deinstallieren und die Lizenz verschenken, aber die Unterstützung durch die Community ist so gut (wie man an Dir sieht), dass ich es dann doch immer mal wieder probiere.

Da gebe ich dir recht @mikel,
ich bin eher im C# Umfeld unterwegs und durch die MS Doku (die ja auch keinen guten Ruf hat) verwöhnt mit zumindest kleinteiligen Beispielen. Problematisch ist sicherlich auch die Nische so das nicht wie bei anderen Systemen riesige FAQ´s im Internet abbilden die von G**gle auch super gefunden werden. Ich würde auch gerne bald mein erstes Modul schreiben aber da gibt es auch so dinge die nicht sofort auf der Hand liegen und somit schaue ich mir Abend für Abend die GitHub Repos von Symcon an um den Flow zu erkennen und für mich umsetzen zu können.

Gruß
Dennis