Hauptmenü

$EVENT vs $EVENTS?

Begonnen von vbs, 12 März 2017, 11:03:15

Vorheriges Thema - Nächstes Thema

vbs

Hi,

ich hätte mal zwei Fragen zu der Eventverarbeitung (hängen irgendwie zusammen).

1. Was ist der Unterschied zwischen $EVENT und $EVENTS?
Die commandref sagt:
$EVENT
für das zugehörige Ereignis

$EVENTS
für alle zugehörigen Ereignisse eines Triggers


Was bedeutet "für alle zugehörigen Ereignisse eines Triggers"? Es kann doch immer nur ein Event gleichzeitig passieren, oder? Wie können zu einem Trigger mehrere Events gehören?

2. Ich verstehe ein Reading meines DOIFs nicht (ähnliche Thematik):
Das ist mein Device:
Internals:
   CHANGED
   DEF        ([env_presence:"^state:"]) ({updateDevices("$DEVICE", "$EVENT")})
   NAME       sys_di_updateDevices
   NR         519
   NTFY_ORDER 50-sys_di_updateDevices
   STATE      cmd_1
   TYPE       DOIF
   Readings:
     2017-03-12 10:06:40   Device          env_presence
     2017-03-12 10:06:40   cmd             1
     2017-03-12 10:06:40   cmd_event       env_presence
     2017-03-12 10:06:40   cmd_nr          1
     2017-03-12 10:06:40   e_env_presence_events state: home,statHomeDuration: Hour: 66.705714448 Day: 660.185474630 Month: 11432.228700591 Year: 23787.504933322 (since: 2017-02-16 ),statHomeDurationDay: 660.185474630,statHomeDurationMonth: 11432.228700591,statHomeDurationYear: 23787.504933322
     2017-03-12 10:06:40   state           cmd_1
     2017-03-12 10:06:40   wait_timer      no timer


Das DOIF soll auf alle state-Events von "env_presence" reagieren. Im Reading "e_env_presence_events" stehen aber offenbar durch Komma getrennt mehrere Events drin. Nämlich "state: home" und die ganzen statistic-Events.

Was bedeutet das? Das DOIF sollte doch mit dem Statistik-Event eigentlich nichts zu tun haben?

Danke euch!

Damian

Ein Trigger ist oft mehr als eine Ereigniszeile. Das kannst du im Eventmonitor am gleichen Zeitstempel erkennen. All die zusammengehörenden Ereignisse werden an ein Modul zum Zeitpunkt des Triggers übergeben. Das sind $EVENTS. $EVENT ist dagegen nur die Zeile die genau zu einem Ereignisfilter passt. Das ist z.B. bei Angaben [device:"regex"] interessant. Bei Angaben [device:reading] nimm ich einfach die erste Ereigniszeile für $EVENT, weil hier auf alle Trigger des Devices reagiert wird, ob das Reading drin vorkommt oder nicht.

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

vbs

Ahh ok danke. Ich vermute mal, dass passiert nur, wenn ein Modul per readingsBeginUpdate/readingsBulkUpdate/readingsEndUpdate mehrere Events auf einmal absetzt? Könnte mir zumindest sonst nicht erklären, wie das technisch funktioniert. FHEM müsste sonst ja eine Zeit lang Events sammeln und sie dann geschlossen den Modulen zustellen.

Damian

Zitat von: vbs am 12 März 2017, 12:46:38
Ahh ok danke. Ich vermute mal, dass passiert nur, wenn ein Modul per readingsBeginUpdate/readingsBulkUpdate/readingsEndUpdate mehrere Events auf einmal absetzt? Könnte mir zumindest sonst nicht erklären, wie das technisch funktioniert. FHEM müsste sonst ja eine Zeit lang Events sammeln und sie dann geschlossen den Modulen zustellen.

Genau. Das sollten alle Module tun, denn dafür sind diese Trigger-Mechanismen geschaffen worden.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PatrickR

Mahlzeit!

Sorry, dass ich diesen Dinosaurierthread defibrilliere, aber mein aktuelles Problem knüpft hier so schön an.

Folgende Situation:
Ich habe ein DOIF geschrieben, was deviceunabhängig verschiedene Fehler-Events von allen Homematic-IP-Geräten sammelt. Das DOIF geht davon aus, dass $EVENT exakt ein Event enthält. Heute Morgen trat allerdings der Fall auf, dass mehrere Events kommagetrennt geliefert wurden, was zu einem kleinen Chaos geführt hat.


defmod D_S_HMIP_Problems DOIF {\
  if ([":^0\.(ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE): \d+"]) {\
  my ($reading, $value) = "$EVENT" =~ m/^(.*):\s+(.*)$/g;;\
  Log(3,"$SELF: Device Event - Device: '$DEVICE', Event: '$EVENT', Reading: '$reading', Value: '$value'");;\
if ($value != 0) {\
set_Timer ("CALLBACK__$DEVICE__$reading", 60);;\
if (ReadingsVal("$SELF", "READINGS", "") !~ m/(^|;;)$reading($|;;)/g) { # DOIF doesnt tolerate square brackets\
my @readings = split(";;", ReadingsVal("$SELF", "READINGS", ""));;\
push(@readings, $reading);;\
set_Reading("READINGS", join(";;", @readings), 0);;\
}\
} else {\
del_Timer ("CALLBACK__$DEVICE__$reading");;\
my $problem_devices = ReadingsVal("$SELF", "PROBLEMS__$reading", "");;\
$problem_devices =~ s/(^|;;)$DEVICE($|;;)//g;;\
set_Reading("PROBLEMS__$reading", $problem_devices, 1);;\
}\
  }\
}\
[zweiter Fall der Timer-Bearbeitung ausgelassen.]


Im Log stand Folgendes:

2018.07.08 11:47:41.767 3: D_S_HMIP_Problems: Device Event - Device: 'UG.KE.Stromzaehler', Event: '0.STICKY_UNREACH: 1,0.UNREACH: 1,hmstate: unreachable', Reading: '0.STICKY_UNREACH: 1,0.UNREACH: 1,hmstate', Value: 'unreachable'
2018.07.08 11:47:41.768 3: eval: D_S_HMIP_Problems: warning in condition c01
2018.07.08 12:04:00.854 3: D_S_HMIP_Problems: Device Event - Device: 'UG.KE.Stromzaehler', Event: '0.UNREACH: 0,1.ENERGY_COUNTER: 729299.300000,1.POWER: 1099.000000,hmstate: Initialized,1.ENERGY_COUNTER_FHEM: 729246.101123,stat1.ENERGY_COUNTER_FHEM: Hour: 1080.100000 Day: 7040.100000 Month: 101453.500781 Year: 705733.501123 (since: 2018-05-24 ),stat1.ENERGY_COUNTER_FHEMHour: 1080.100000,stat1.ENERGY_COUNTER_FHEMDay: 7040.100000,stat1.ENERGY_COUNTER_FHEMMonth: 101453.500781,stat1.ENERGY_COUNTER_FHEMYear: 705733.501123', Reading: '0.UNREACH: 0,1.ENERGY_COUNTER: 729299.300000,1.POWER: 1099.000000,hmstate: Initialized,1.ENERGY_COUNTER_FHEM: 729246.101123,stat1.ENERGY_COUNTER_FHEM: Hour: 1080.100000 Day: 7040.100000 Month: 101453.500781 Year: 705733.501123 (since: 2018-05-24 ),stat1.ENERGY_COUNTER_FHEMHour: 1080.100000,stat1.ENERGY_COUNTER_FHEMDay: 7040.100000,stat1.ENERGY_COUNTER_FHEMMonth: 101453.500781,stat1.ENERGY_COUNTER_FHEMYear', Value: '705733.501123'


Nach der Info oben sollte $EVENT ausschließlich das matchende Event, nämlich 0.UNREACH enthalten.
Was übersehe ich?

Patrick
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

Damian

#5
Ich habe gerade im Sourcecode nachgeschaut, bei EventTriggerabfragen wie in deinem Fall, wird eine kommagtrennte Liste der zusammengehörenden Events in $event abgelegt:

$hash->{helper}{event}=join(",",@{$eventa})


In den Ferien werde ich mir die Sache genauer anschauen, denn bei Eventabfragen sollte eigentlich nur das passende Event gespeichert werden.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PatrickR

#6
Danke Dir!

Muss ich mal sehen, wie ich damit umgehe...  Hast Du zufällig ne Idee für einen temporären Workaround (ohne die Liste der interessanten Readings zu doppeln)?


Von unterwegs gesendet.
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

Damian

Zitat von: PatrickR am 08 Juli 2018, 23:14:37
Danke Dir!

Muss ich mal sehen, wie ich damit umgehe...  Hast Du zufällig ne Idee für einen temporären Workaround (ohne die Liste der interessanten Readings zu doppeln)?


Von unterwegs gesendet.

Mit split könntest du die Events in einer Schleife prüfen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PatrickR

Zitat von: Damian am 09 Juli 2018, 08:00:19
Mit split könntest du die Events in einer Schleife prüfen.
Wie mache ich das, ohne die Liste der interessanten Readings zu doppeln?


Von unterwegs gesendet.
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

Damian

Zitat von: PatrickR am 09 Juli 2018, 18:14:27
Wie mache ich das, ohne die Liste der interessanten Readings zu doppeln?


Von unterwegs gesendet.

foreach my $e (split(",",$event)) {
my ($reading, $value) = $e =~ m/^(.*):\s+(.*)$/g;
...
}


sollte funktionieren.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Ich habe das Problem gefunden.

Im FHEM-Modus ist die Bedingung und der Ausführungsteil getrennt, dort beinhaltet $EVENT tatsächlich den Match.
Im Perl-Modus entspricht der ganze Block der DOIF-Bedingung im FHEM-Modus (wird mit eval ausgewertet), DOIF kommt nicht mehr dazwischen um $EVENT vorzubelegen.

Der Match der letzten Eventabfrage ist allerdings intern unter $hash->{helper}{event} abgelegt.

Daher reicht:

my ($reading, $value) = "$EVENT" =~ m/^(.*):\s+(.*)$/g;

durch

my ($reading, $value) = $hash->{helper}{event} =~ m/^(.*):\s+(.*)$/g;

zu ersetzen.

Da wollen wir hoffen, dass der undokumentierte Hack zukünftig immer noch funktioniert. ;)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Eine weitere Alternative ohne Hacks ist DOIF-Filter zu verwenden. Dann braucht man noch nicht mal if.

statt
Zitatif ([":^0\.(ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE): \d+"]) {
     my ($reading, $value) = "$EVENT" =~ m/^(.*):\s+(.*)$/g;

definieren:

Zitatmy $event =[":^0\.(ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE): \d+":"(.*)",0];
my ($reading, $value) = $event =~ m/^(.*):\s+(.*)$/g;
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PatrickR

#12
Hallo Damian,

damit wir uns nicht missverstehen. Mir ging es nur um einen Tipp, wie ich das Doppeln der Readings verhindere, nicht um einen Grundkurs in der geheimen Kunst der Stringverarbeitung :)

Letztlich - korrigiere mich, wenn ich falsch liege - kann kann ich die Doppelung (gemeint ist die des Strings ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE) nur mit der Hack-Variante mit dem helper umgehen. Die werde ich mir jetzt näher ansehen.

Interessant dürfte vor allem sein, was passiert, wenn mehrere matchende Events in einem Stapel vorbeikommen. Wie willst Du in der gefixten Version damit umgehen? Die Events vereinzeln und den Ausführungsteil mehrfach ausführen oder übergibst Du dann in $EVENT die Liste der matchenden(!) Events?

Patrick

lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

Damian

Zitat von: PatrickR am 09 Juli 2018, 21:10:57
Hallo Damian,

damit wir uns nicht missverstehen. Mir ging es nur um einen Tipp, wie ich das Doppeln der Readings verhindere, nicht um einen Grundkurs in der geheimen Kunst der Stringverarbeitung :)

Letztlich - korrigiere mich, wenn ich falsch liege - kann kann ich die Doppelung (gemeint ist des Strings ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE) nur mit der Hack-Variante mit dem helper umgehen. Die werde ich mir jetzt näher ansehen. Interessant dürfte vor allem sein, was passiert, wenn mehrere matchende Events in einem Stapel vorbeikommen.

Patrick

Was verstehst du unter Dopplung? Wenn du alle Events eines Event-Blocks meinst, dann funktioniert das, wie beschrieben,  nicht in der Perl-Variante mit $EVENT bzw. $event als echte Perlvariable.

Unabhängig davon wird nur der erste Match eines Events-Blocks gespeichert, denn dann ist die Bedingung bereits wahr und es wird nicht weiter geprüft (dafür sind in erster Linie die Eventabfragen ["..."] programmiert worden).

Wenn du alle Events eines Event-Block (gleicher Zeipunkt) auswerten willst, dann musst über die Schleife gehen - mein Beispiel mit foreach-Schleife.


Meistens kommt aber immer nur ein Event-Typ (Reading) in einem Event-Block vor, wie eine z. B. Fehlermeldung ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

PatrickR

#14
Zitat von: Damian am 09 Juli 2018, 21:29:09
Was verstehst du unter Dopplung?

Ich meine, dass ich die Liste der interessanten Readings sowohl in der DOIF-Bedingung als auch in der foreach-Zerlegung des Eventstapels benötige:

{
  if ([":^0\.(ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE): \d+"]) { # <<<<<<<<<<<<<<<<< Dopplung 1
  my ($reading, $value) = "$EVENT" =~ m/^(.*):\s+(.*)$/g;
  Log(3,"$SELF: Device Event - Device: '$DEVICE', Event: '$EVENT', Reading: '$reading', Value: '$value', hash->{helper}{event}: '" . $hash->{helper}{event} . "'");
foreach my $e (split(",",$event)) {
my ($reading, $value) = $e =~ m/^(0\.ERROR_CODE|0\.ERROR_OVERHEAT|0\.UNREACH|0\.DUTY_CYCLE)):\s+(.*)$/g; # <<<<<<<<<<<<<<<<<<<<<<<<<<<< Dopplung 2
    # Dieser Teil soll nur für die relevanten Readings ausgeführt werden, nicht für den Beifang
}
}

Hast Du eine Idee, wie ich das umgehe?

Zitat von: Damian am 09 Juli 2018, 21:29:09
Meistens kommt aber immer nur ein Event-Typ (Reading) in einem Event-Block vor, wie eine z. B. Fehlermeldung ERROR_CODE|ERROR_OVERHEAT|UNREACH|DUTY_CYCLE
Ich fürchte, dass das in meinem Fall problematisch ist, weil bestimmte Fehler mehrere Readings in einem Schlag aktualisieren und die möchte ich ungern verpassen.

Zitat von: Damian am 09 Juli 2018, 21:29:09
Unabhängig davon wird nur der erste Match eines Events-Blocks gespeichert, denn dann ist die Bedingung bereits wahr und es wird nicht weiter geprüft (dafür sind in erster Linie die Eventabfragen ["..."] programmiert worden).
Ich hatte es befürchtet, und leider auch gerade verifiziert, da es programmiertechnisch Sinn ergibt.

Patrick

/Edit: Codebeispiel war falsch, bitte als Pseudocode sehen :)
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook