Events auf ganzen Objektbaum

Hallo zusammen

Gibt es eine Möglichkeit Events auf einen ganzen Objektbaum zu setzen? D.h. wenn irgend eine Variable innerhalb eines Baumes sich ändert, ein Skript aufzurufen?

gruss over.unity

Tut mir leid, gibt es nicht.

paresy

Wie macht Ihr dann das so? Für jedes gewünschte Objekt ein Ereignis?

EDIT:
Könnte man den VariableManager überwachen oder das log? Hier wird ja alles bei einer Änderung eingetragen…

Ich mache sowas indirekt über eine Datenbank. Ich schreibe sowieso bestimmte (de facto fast alle) Daten in eine Datenbank, muß dazu nur die Variable „onChange“ oder „onUpdate“, je nachdem was ich erfassen will, an einem einzigen Script „dbWrite“ triggern, was das einträgt.

Das landet in der DB dann in einer einheitlichen „Messdaten“-Tabelle, wo wiederum jedes Record zur Identifizierung einen Zeiger auf eine „Objekte“-Tabelle hat, welche die Instanzen enthält. Diese Objekte-Records haben wiederum Rekursionszeiger, und bilden damit die Hierarchie ab.

…und dann gibt es so wunderbare Dinge, wie Datenbank-Trigger, mit denen man dann eigentlich alles, u.a. auch das „triggern am ganzen Baum“ erledigen kann und auch wieder den Rückfluß der Info ins IPS sichert.

Ich denke hier das Log zu parsen ist der einfachere und elegantere Weg. Wobei in V1 die Variablen in ein array müßten. Weil hier soweit ich weiß der Objektbaum nicht übermittelt wird. In V2 könnte das anders sein, hab ich aber noch nicht probiert.

okay, das ist eine gute Methode, aber dann hast Du ja auch einzelne Events auf den Objekten… nur wie machst Du das? jedes Objekt einzeln erfassen?

Verstehe ich nicht ganz. Wo hast Du die Funktion oder wie Du das sagst „onChange“? Auf der DB oder unter IPS? Wenn IPS, was ist das für eine Funktion?

Trigger? Was für eine DB verwendest Du?

Ist interessant! Weisst Du wie ich zu diesem Array komme?

Hey, aber danke an Euch zwei für die Beiträge!

gruss over.unity

gruss over.unity

Um Dein Poblem zu lösen und vieleicht noch einen anderen Weg zu finden, warum möchtest Du eine ganze Gruppe von Variablen als Eventtrigger benutzen. gwanjek meint mit „onChange“ oder „onUpdate“, sobald die Variable aus Deinem zu überwachendem Bereich geändert wird - triggert(startet) diese ein Log Script. Und in diesem kannst Du dann „lustige“ Dinge machen.

Also Du meinst damit, das log File auslesen und auf Veränderungen überwachen?

gruss over.unity

EDIT
Habs kurz angeschaut, dies wäre aber sehr ineffizient, jedes mal das log file zu parsen. 1. hast Du verschiedene Logfiles welche nach Datum zu überprüfen sind und 2. Du musst jedesmal das ganze File parsen um an neue Informationen heran zu kommen. Was ist aber, wenn ich pro Sekunde diese Information prüfen möchte?

Richtig, in diesem Fall ist, wenn so kurze Zyklen verwendet werden, ein anderer Weg sinnvoll.

Wie viele Variablen sollen überwacht werden?

Ich denke mann sollte hier eine Automatikroutiene schreiben die die Events und die Variablen automatisch anlegt. Oder sind diese schon vorhanden?

Und ein Logscript verwenden welches diese überwacht. So wie gwanjek schon vorgeschlagen hat.

So mache ich das z.B. (nur ein kleine Auszug aus meinem Logscript):


 include(IPS_GetScriptFile("Konstanten"));

 //----------------------------- Updatezeiten ----------------------------------

 //Variablen die geprüft werden sollen
 $var = array
 (
   IPS_GetUpdateTime("EG_Au_Bewegungsmelder_Status"),
   IPS_GetUpdateTime("KG_Flu_Bewegungsmelder_Status"),
   IPS_GetUpdateTime("EG_Flu_Bewegungsmelder_Status"),
   IPS_GetUpdateTime("OG_Flu_Bewegungsmelder_Status"),
   IPS_GetUpdateTime("OG_Bad_Bewegungsmelder_Status"),
   IPS_GetUpdateTime("Geragentor"),
   IPS_GetUpdateTime("OG_Bal_Daemmerungssensor_Status"),
   IPS_GetUpdateTime("KG_Wa_Fertigmelder_Status"),
   IPS_GetUpdateTime("OG_Bad_Bewegungsmelder_Status_2")
 );

 $var_anz = count($var); //Variablen zählen

 for ($i=0; $i<$var_anz; $i++)
 {
   //fürende Null hinzufügen
   $b = getdate($var[$i]);
   $GetUpdateTime_[$i] = date("d.m./H:i",$b[0]);
   $zeitwert = GetValueString("GetUpdateTime_$i");
   if($GetUpdateTime_[$i] != $zeitwert) //nur Variable bei Änderung schreiben
   {
      SetValueString ("GetUpdateTime_$i", $GetUpdateTime_[$i]);
   }
 }

 //------------- Loggen von wichtigen Variablen- & Scriptänderungen ------------

 if ($IPS_SENDER == "Variable")
 {
   $log_variable = $IPS_VARIABLE; // Variable die getriggert hat
   $log_variablen_wert = $IPS_VALUE; // Wert der Variablen
   $log_variablen_typ = IPS_GetVariableType($IPS_VARIABLE); // Variablentyp bestimmen
 }
 //Variablentypen Texte zuweisen
 if ($log_variablen_typ == "Boolean" and $log_variablen_wert =="1")
 {
   $log_variablen_wert = "an";
 }
 else
 {
   if ($log_variablen_typ == "Boolean")
   {
      $log_variablen_wert = "aus";
   }
 }

 //----------------- aktuellen Trigger im Textfile schreiben -------------------

 // diese Werte nicht aufzeichnen
 if($log_variable == "log_menge"){return;}
 //if($log_variable == "trig_ips_component" and $log_variablen_wert == ""){return;}
 if ($IPS_SENDER == "Designer")
 {
   if($IPS_COMPONENT == "filter")
   {
      return;
   }
 }
 //aktelle Meldung
 $log_datum = date("d.m.y"); //Logdatum
 $log_zeit = date("H:i:s");  //Logzeit

 $log_datum2 = date("m.y"); // Logfile nach Monaten aufteilen

 // ==> durch Variable getriggert
 If ($log_variable == "OG_Bal_Daemmerungssensor_Status")
 {
   $log_zeit = IPS_GetUpdateMicrotime($log_variable);
   $ms       = explode(".", $log_zeit);
   $log_zeit = date("d.m. H:i:s:".$ms[1], $log_zeit);

   $log_variable = "Licht eingestellt auf: ";
   
   If ($log_variablen_wert == "an")
   {
      $log_variablen_wert = "Nachtmodus";
   }
   else
   {
      $log_variablen_wert = "Tagesmodus";
   }

   $handle=fopen("c:/IP-Symcon/Thomas/logfile_$log_datum2.txt", "a");
   fwrite($handle, $log_zeit.", ".$log_variable.$log_variablen_wert."
");
   fclose($handle);
   return;
 }

also nochmal:

  1. Schritt:
    in IPS ändern sich Variablen, die ich überwachen bzw. einfach nur aufzeichnen will in der Datenbank. Dazu gibt es ein IPS-Script (heißt bei mir „dbWrite“), welches in IPS an den zu überwachenden Variablen getriggert ist, eben onupdate oder onchange, je nachdem ob mir auch wichtig ist DAS ein neuer Wert kam, oder eben nur wenn der sich geändert hat. Die zweite Sorte Trigger bekommen wir später… :slight_smile:

In der Datenbank existieren (vereinfachen wir mal) 2 Tabellen mit einer ForeignKey-Beziehung dazwischen (Zeiger von einer zur anderen Tabelle). Einmal „Messdaten“ mit (als wichtigste / vereinfacht) 3 Feldern: Daten (varchar = „string“ damit alle Formate passen), einem Datumsfeld „gueltigab“ und eben dem Zeiger auf die zweite Tabelle namens „Objekte“ in der sozusagen die Instanzen abgespeichert werden. Somit ist, obwohl alles an Daten „geradeaus“ in eine Tabelle geschmissen wird, jedes Ereignis nachvollziehbar. Dank des „gueltigab“ gilt das sogar in der Historie, also wie kam es zu einem Wert zu einem bestimmten Zeitpunkt. Man nennt das „Daten im Zustandsraum“, also Daten die den gesamten Systemzustand zu einem bestimmten Zeitpunkt beschreiben.

Wem jetzt bedenken kommen wegen zu großer Datenmengen, Zugriffzeiten usw: Stichwort Indizierung. Damit klarzukommen, dafür sind Datenbanken da. Mehrere Mio Records auf nicht mehr ganz neuem PC als „Server“, trotzdem Echtzeitabruf (XP, MS-SQL). Der Preis: 2GB RAM sollten schon sein. Und ein gutes Index-Design…

Die „Objekte“-Tabelle wiederum hat noch einen 2. ForeignKey, der auf die Tabelle selbst verweist. Damit können Rekursionen, also Hierarchien abgebildet werden. „Objekt ist Unterobjekt von…(Zeiger auf übergeordnetes Objekt)“.

Die Objekte generiere ich durch zyklisches Einlesen der Settings.xml bzw. die werden direkt eingetragen beim Eintrag eines Datenwertes im dbWrite-Script, so das Objekt im dem Moment in der Objekte-Tabelle noch fehlen sollte (der Hierarchienzeiger wird dann aber erst bein nächsten zyklischen Einlesen der settings aktualisiert).

In der V1 realisiere ich Hierarchien übrigens per Namensnotation: Jede Instanz hat einen eindeutigen Namen, jede zugehörige Variable einen Namen mit einem Präfix aus dem Instanzennamen, Trenner ist ein Punkt. Das ganze gilt auch auf mehreren Ebenen. Beispiel: HMS100-Wassermelder Hauswirtschaftsraum/Waschmaschine: Instanz: „h2oHWR“, Statusvariable: „h2oHWR.Status“, Überwachungsvariable zur Statusvariable für „Sensor verloren“: „h2oHWR.Status.lost“, zugehöriger Zeitstempel: „h2oHWR.Status.lost.time“ usw.

Soweit erstmal die prinzipielle Datenerfassung.

  1. Schritt:
    Innerhalb der Datenbank gibt es nun wiederum Datenbanktrigger. Dort kann man ähnlich wie im IPS sozusagen spezielle SQL-Scripts hinterlegen, abhängig davon, ob ein Record bzw. eine Tabellenspalte oder auch die Tabelle selbst angefaßt werden (Insert-, Update- und Delete-Trigger). Bei Update kann man auch noch mit den Werten selber spielen.

Nun haben wir ja die Objekttabelle und die dort rekursiv verweisenden Zeiger. Überwache ich dort ein „Hilfsfeld“ bzgl. Update (z.B. Zeitstempel, wann Daten dieses Objekttyps zuletzt aktualisiert wurden, also letztes Eintrags-Ereignis per „dbWrite“), kann ich somit auch die Objekte selbst rekursiv überwachen. Im zugehörigen DB-Trigger steht dann nur noch eine Rekursions-Abbruchbedingung bzgl. eines Objekt-Kennzeichens. Name oder V2-kompatibel Instanznummer. Voila, und an dieser „Abbruchbedingung“ hängt dann meine Aktion, die ich „am ganzen Zweig der Hierarchie wirkend“ haben möchte.

Klingt vielleicht alles etwas kompliziert, aber für mich ist es einfacher als andere Lösungen. Zum einen habe ich sehr sichere und stabile Werteerfassung, bei sehr schnellem Zugriff nebst Parallelisierungs-Verriegelung usw durch die DB-Engine selbst. Zum anderen erfasse ich sowieso meine Werte in der DB, allein schon um z.B. mit zeitlich fließenden Grenzen bei variablem Grenzwert („letzte 24h“, „letzte 3h“…) statistisch rückwirkende Dinge ermitteln zu können. Beispiel: Wann ist Sturmwarnung eigentlich aufgehoben? Stichworte: Böen und nur alle 6-10min Daten von der KS300. Einmal „geringe Windgeschwindigkeit unter Grenzwert“ ist noch lange nicht Sturmende! usw. Man stelle sich das variablenorientiert vor! Allein der Gedanke, auch mal nachts um 2:43 eine Aussage bzgl. der Standardabweichung der Werte der letzten 5 Stunden treffen zu müssen (also fließend über Tagesgrenze hinweg)… In SQL ein Einzeiler.

Gruß Gerd

Edit:

Wem nun Bedenken kommen sollten wegen „ja aber das können ja nur die großen DB-Engines“ …klar, aber auch die gibt es kostenfrei als Runtimeversion (MS-SQL z.B. als „Express edition“). Und auch ohne die komfortablen Entwicklerumgebungen kann man die wunderbar z.B. per Access managen