Hallo!
Ich habe eine richtige Anfängerfrage, als FHEM und Perl Neuling. Ich möchte innerhalb eines Notify mittels FHEM Befehls ein at schedulen, worin wiederum ein Perl Script steht, in dem dann wieder ein FHEM Befehl ausgeführt wird. Mein Notify funktioniert soweit, daher paste ich das hier jetzt mal nicht rein, um die Sache übersichtlicher zu machen.
Folgender Teil funktioniert nicht:
{fhem ("define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value("TFKontaktEingang") eq "closed") {fhem ("set KeyMaticEingang lock")}}")}
Führe ich diesen Teil direkt in FHEM aus klappt es:
define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value("TFKontaktEingang") eq "closed") {fhem ("set KeyMaticEingang lock")}}
Was mache ich falsch?
Liebe Grüße,
Max
Hi Max,
besser ist trotzdem mal nicht wegzulassen, evtl. sieht es (manchmal) so aus als würde ein Teil klappen aber dann ist genau dort der Anfang vom Ende ;-)
und "Code-Schnipsel" in "code-tags" packen das ist das '#' in der Menüleiste...
Aber ich denke es hat mit den Anführungszeichen zu tun:
der erste "String" ist ja
"define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value("
und nicht "define at_Eingangstuere_zusperren2 at +00:00:10 DOSOMETHING"
Mal die " in der Mitte durch ' ersetzen oder "escapen"...
Was ich bei sowas mach ist, dass ich den "Ausführteil" in eine sub in my_Utils auslagere und dann im notify / at etc. nur diese Sub aufrufe, die macht dann den Rest...
Eventuell mal devmod statt define, gibt Fehler, wenn das 'at' bereits definiert ist (also ab dem 2ten Aufruf)...
Ich habe folgendes bei mir:
{fhem("defmod Reset_Heating_ZiVier_Delayed at +00:00:10 {ResetHeatingZiVier()}")}
D.h. die Heizung wird erst 10min nach Fenster closed wieder hich gedreht...
...Hochdrehen der Heizung wird dann durch die Sub 'ResetHeatingZiVier' erledigt, da ich dort noch so einiges prüfe etc.
Gruß, Joachim
Also der ganze Code sieht so aus:
define n_Eingangstuere_zusperren notify TFKontaktEingang {
my $time = sprintf("%02d:%02d", $hour, $min);;
if ((Value("TFKontaktEingang") eq "closed") && (($time gt "21:00") || (($time gt "00:00") && ($time lt "07:00")))) {fhem ("define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value("TFKontaktEingang") eq "closed") {fhem ("set KeyMaticEingang lock")}}")}}
Doppelte at's sind nicht mein Problem - die sind nach 10 Sekunden ohnehin wieder weg ...
Danke für den Tipp! Ich habe es jetzt so implementiert und es funktioniert nun:
TFKontaktEingang {
my $time = sprintf("%02d:%02d", $hour, $min);;
if ((Value("TFKontaktEingang") eq "closed") && (($time gt "21:00") || (($time gt "00:00") && ($time lt "07:00")))) {fhem ("define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value('TFKontaktEingang') eq 'closed') {fhem ('set KeyMaticEingang lock')}}")}}
Hi Max,
freut mich...
Allerdings:
der mit define angelegte 'at' bleibt (normalderweise), also der Name ist in fhem vergeben.
Legst du das 2te Mal den selben 'at' gleicher Name an (also 2ter Durchlauf des notify), dann gibt es den 'at' mit dem Namen schon und es wird wohl eine Fehlermeldung kommen.
War zumindest bei mir so, daher 'defmod' statt 'define'...
Richtig ist: der 'at' löst nur einmal nach 10sek aus, der definierte 'at' bleibt aber in fhem bestehen (mind. bis zum shutdown restart und wenn irgendwann ein save config folgt sogar darüber hinaus)...
Aber wenn das bei dir nicht auftritt: gut! ;-)
Gruß, Joachim
hmmm ... also bei mir ist der AT gleich nach dem ausführen weg ... jedenfalls wenn ich ihn mit +00:00:10 anlege ...
Ein at bleibt nur so lange bestehen wie es mit * als sich wiederholend angelegt wurde.
Was ich bisher in Deinem Code sehen konnte war das es sich um sehr kurzlebige at's handelt. Hier kannst Du mit einem FHEM sleep besser arbeiten
{ fhem ("sleep 10; set KeyMaticEingang lock") if (Value("TFKontaktEingang") eq "closed") }
Ich weiß nicht mehr ganz genau wie es sich verhält wenn das sleep der erste FHEM Befehl ist. Aber probiere das erstmal so.
Grüße
Leon
Hi,
ah, ok.
Vielleicht hatte ich auch beim Rumprobieren mal andere 'at'...
Bleibe (da es läuft) aber (erst mal) bei defmod...
Gruß, Joachim
Das mit dem FHEM sleep hatte ich vorher ... das Problem ist, dass ich nach den 10 Sekunden nochmal prüfen möchte ob die Türe immer noch zu ist ... FHEM sleep blockiert außerdem wenn aus PERL Code heraus aufgerufen das System ... zumindest war das bei mir so.
Das kann ich definitiv verneinen, da Du ja das sleep aus dem FHEM Kontext heraus aufrufst.
Und um zu schauen ob nach x Sekunden ein bestimmter Status noch vorhanden ist nimmt man watchdog
Am besten Du zeigst uns mal dein gesamtes Konzept was Du gerade am bearbeiten bist. Was genau willst Du erreichen?
Ah ... Watchdog ;-) ... muss ich mir ansehen, kannte ich noch nicht ;-).
Ich habe euch das ganze Ding gezeigt, aber hier gerne nochmals. So ist es jetzt implementiert und funktioniert:
define n_Eingangstuere_zusperren notify TFKontaktEingang {
my $time = sprintf("%02d:%02d", $hour, $min);;
if ((Value("TFKontaktEingang") eq "closed") && (($time gt "21:00") || (($time gt "00:00") && ($time lt "07:00")))) {fhem ("define at_Eingangstuere_zusperren2 at +00:00:10 {if (Value('TFKontaktEingang') eq 'closed') {fhem ('set KeyMaticEingang lock')}}")}}
Was soll es tun? (tut es jetzt auch!)
- Auslösen wenn die Türe zwischen 21:00 Abends und 07:00 Früh geschlossen wird (Türkontakt)
- Nach 10 Sekunden prüfen ob die Türe immer noch geschlossen ist
- Falls ja, zusperren
Wenn es dafür eine bessere Lösung gibt setze ich das auch wirklich sehr gerne anders um! ich bin ja vollkommen neu bei FHEM und hatte bisher auch nie Perl programmiert, also kenne ich die Feinheiten noch nicht.
Wie gesagt. Watchdog wäre gut.
Ein watchdog prüft ob der Auslösezustand nach x Zeit noch vorhanden ist wenn ja führe aus.
Hast Du Dich schon mit Anwesenheitserkennung befasst? Hier könnte man das ganze Abhängig vom Bewohnerstatus besser realisieren. Schließe ab wenn alle Bewohner weg sind oder wenn alle Bewohner schlafen.
Ich habe mir Watchdog jetzt angesehen; mein Problem ist, dass dafür alles mit Regular Expressions ausgedrückt werden muss und ich damit nicht fit bin. Ich habe keine Ahnung, wie ich die mit den ifs abgebildeten Bedingungen durch RegExs ablöse.
Die Erste wäre ja mal: Wenn innerhalb eines gewissen Uhrzeitfensters die Türe zu gemacht wird.
Und die Zweite: Wenn sie 10 Sekunden danach immer noch zu ist.
Wie würde ich diese beiden Abfragen durch RegExs ausdrücken? Also ganz konkret: Wie würde der äquivalente Watchdog zu meinem Miniprogramm aussehen?
Zitat von: CoolTux am 19 Juni 2016, 14:22:16
Ich weiß nicht mehr ganz genau wie es sich verhält wenn das sleep der erste FHEM Befehl ist.
Das ist kein Problem!
Nur wenn direkt
nach dem
Sleep kein weiterer Befehl mehr kommt, dann blockiert es.
Anhand Deiner Frage stelle ich fest das Du noch nicht so ganz watchdog verstanden hast. Versuche mal andersrum zu denken.
Ziel ist es das die Tür zugeschlossen werden soll wenn sie zu gemacht wurde und innerhalb von 10m nicht wieder auf gemacht. Dabei gilt zu beachten das der Schaltbefehle nur zwischen bla und bla ausgeführt werden soll. Lass also den watchdog ruhig anspringen und im Schaltbefehl fragst dann die Uhrzeit an
define w_Eingangstuer_zusperren watchdog TFKontaktEingang.closed 00:10 TFKontaktEingang.closed { if (($time gt "21:00") || (($time gt "00:00") && ($time lt "07:00")))
fhem ("set KeyMaticEingang lock; trigger w_Eingangstuer_zusperren .");
}
Bitte noch mal anschauen und kucken ob das if so ok ist. Habe auf Tablet geschrieben.
OK. Man würde also gar keine RegEx dafür verwenden, sondern einfach wieder Perl ... verstehe.
Zwei Probleme sehe ich noch mit Deinem Beispiel:
1. Die zweite RegEx muss doch false sein, damit der der WatchDog auslöst, oder verstehe ich das falsch? Im Wiki ist der Watchdog ja wie folgt definiert: "Führe Befehl <command> aus, wenn nach Ereignis <regexp1> nicht innerhalb der Zeitspanne <timespec> das Ereignis <regexp2> auftritt." Insofern dürfte man nicht auf TFKontaktEingang.closed abfragen, oder? Ich will aber auch nicht auf .open abfragen, weil auch noch andere Stati vorhanden sein können, sondern eben eine RegEx die closed verneint. Aus WatchDog Sicht wäre es also: wenn zu und nach 10 Sekunden nicht nicht zu, dann ...
2. Im Perl Teil fehlt noch das Auslesen der Zeit und speichern in der Variable $time. Aber das ist mir klar und brauche ich ja bloß aus meiner bisherigen Implementierung kopieren.
Gut auf gepasst. Ja Du hast Recht. Beim zweiten muss open stehen.
define w_Eingangstuer_zusperren watchdog TFKontaktEingang.closed 00:10 TFKontaktEingang.open { if....
Ich will aber eben nicht auf open prüfen, sondern auf alles außer closed. Und genau das weiß ich nicht wie es geht ...
Das verstehe ich nicht. Der Zustand einer Tür kann doch nur open oder closed sein. Was soll denn da noch ab zu fragen gehen.
Der Sensor liefert auch andere Werte zurück; mir geht es prinzipiell darum wie ich bei Fhem mit einer RegEx eben nicht auf einen bestimmten Wert prüfe, sondern alles außer einem bestimmtem Wert.
du kannst in perl doch auch negieren. Ich weiß jetzt die String Vergleichsoperatoren nicht, schätze mal 'not equal "open"'
Irgendwie reden wir aneinander vorbei.
Erstmal geht es darum das der watchdog aus löst, auslösen kann er nur bei einem Ereignis (Trigger). Hier kann man nicht auf nicht Ereignisse eine RegEx setzen.
Kann aber sein das ich Dich nicht verstanden habe. Dachte bis jetzt die Aufgabenstellung bestünde nur darin das wenn die Tür zu gemacht wird und nicht innerhalb einer bestimmten Zeit wieder auf das dann das Türschloss zwischen bestimmten Zeiten verschließen soll. Wenn da jetzt noch mehr ist fehlt mir die Info.
Ja Dein Türsensor liefert auch andere Werte. Batterie vielleicht und sabotageError. Frage ist nur ob das relevant ist für Dein Schließvorgang.
Zitat von: MaxAut am 25 Juni 2016, 11:14:41
Ich will aber eben nicht auf open prüfen, sondern auf alles außer closed. Und genau das weiß ich nicht wie es geht ...
... ne 'closed'
In diesem Fall hast Du wohl recht und es macht keinen Sinn auf nicht closed abzufragen, aber es geht mir auch ums Allgemeine; ich will wissen, wie ich mit einer RegEx verneine, bzw. wie diese RegEx generell funktionieren - ich finde leider kaum Beispiele (die auch kommentiert sind, sodass man etwas daraus lernen könnte ...).
... ne 'closed'
--> Das würde doch nur für ein if gehen, oder?
Kann mir irgendjemand sagen, wie ich in nachstehender Zeile den Teil "TFKontaktEingang.open" durch ein "TFKontaktEingang.<alles andere außer closed>" ersetze?
define w_Eingangstuer_zusperren watchdog TFKontaktEingang.closed 00:10 TFKontaktEingang.open { if....
was hast du denn die ganze Zeit mit RegEx, die benutzt du doch überhaupt nicht?
Es gibt eine millionen Möglichkeiten zu testen und darauf zu reagieren. Mit if, elseif, else zb. Dann kannst du dir das DOIF mal anschauen, da sind genug Beispiele. http://www.fhemwiki.de/wiki/DOIF
Wir drehen uns im Kreis ... das ist mir schon klar; sobald ich es in Perl mache habe ich auch kein Problem.
Die eigentliche Aufgabenstellung ist: Wenn ein Kontakt geschlossen ist, schaue 10 Sekunden später nach ob er das immer noch ist, und wenn ja reagiere darauf. Derzeit habe ich es in Perl implementiert, wie ja auch in diesem Thread zu lesen ist. Dann wurde empfohlen ich soll Watchdog nehmen. Das will ich nun auch tun, allerdings fehlt mir eben die zweite RegEx.
Nochmal: Ich will es nicht in Perl realisieren, sondern eben mit diesem Watchdog, und der hört laut WIKI nunmal auf RegEx.
Ah sorry, ich habe leider nicht mitbekommen, dass wir schon beim watchdog sind. (Den wollte ich dir für den Use-case gerade vorschlagen :o )
Deine zweite RegEx könnte im Endeffekt auch einfach komplett offen sein (.*) sein: Der Watchdog prüft das zweite RegEx ja erst, wenn das erste zuvor auch eingetreten ist, also in deinem Fall closed. Wenn jetzt eine weiter Zustandsänderung auftritt, kann die ja nur was anderes sein, als closed, da dieser Zustand ja bereits erreicht ist. Das sollte funktionieren, sofern event-on-change-reading auch korrekt gesetzt ist, so dass das closed-Event auch nur 1 mal auftreten kann.
Das verstehe ich nicht ... die zweite RegEx ist soweit ich WatchDog verstanden habe doch kein Event, oder? Die Erste ist der Event auf den der WatchDog reagiert, die Zweite ist dann die Prüfung die der WatchDog nach Ablauf der angegeben Zeit selbständig prüft.
Das ich .* nehmen kann ist mir klar, aber dann würde ich es ja wieder in Perl abhandeln. Ich will den WatchDog einfach gesagt so einsetzen wie er gedacht ist, und ihn selbst die zweite RegEx prüfen lassen. Er "feuert" ja, wenn die zweite RegEx false ist; zumindest lese ich das aus der Wiki Beschreibung heraus. Das einzige was mir fehlt ist das Wissen wie ich die zweite RegEx schreibe. Ich will eben nicht schreiben .open (dass das funktionieren würde ist mir schon klar, denn das wäre false wenn die Türe zu ist, und damit würde das folgende Kommando ausgeführt werden und damit auch den Sinn erfüllen), sondern <jeder andere Status außer closed>. Warum? Einfach weil ich grundsätzlich interessiert an diesem RegEx Zeug bin und das lernen möchte. Im wesentlichen reduziert sich meine Frage eigentlich darauf, wie ich die Prüfung TFKontaktEingang.closed verneinen kann.
Nein!
Der Watchdog (Wachhund) befindet sich ursprünglich quasi in einem "Schlafzustand" und wacht bei einem Ereignis auf, das von RegEx 1 abgedeckt wird. Dann wartet er (er wacht) bis die angegebene Zeit abgelaufen ist und führt dann den angegebenen Ausführungsteil aus (Wachhund bellt). Tritt allerdings während der Wartezeit (Wach-Zeit) ein Ereignis auf, das von RegEx 2 abgedeckt wird, dann geht er wieder den "Schlafzustand" zurück, bis wieder in ein Ereignis auftritt, das von RegEx 1 abgedeckt wird.
Wurde übrigens der Ausführungsteil einmal ausgeführt (Hund hat gebellt) geht er nicht automatisch wieder in den "Schlafzustand" zurück. Es sei denn man setzt beim Watchdog das Attribut
autoRestart (oder triggert den Ihn nach der Ausführung mit einem Punkt .)
Zitat von: MaxAut am 25 Juni 2016, 19:05:02
Das ich .* nehmen kann ist mir klar, aber dann würde ich es ja wieder in Perl abhandeln.
Das ist RegEx und kein Perl!
OK, verstanden; die zweite RegEx ist ebenfalls ein Event auf das gewartet wird, und bei Nichteintritt innerhalb der angegeben Zeit wird ausgeführt.
Aber dennoch bleibt meine Grundfrage: Wie lautet die RegEx für alle anderen Events außer ein bestimmter? In meinem Beispiel alles andere außer "closed".
Da kann ich dir jetzt leider auch nicht weiterhelfen, da müssen dir RegEx-Profis antworten. Ich weiß nur wie man mit RegEx einschließt (match). Ob und wie man bei RegEx ausschließen würde mich aber auch interessieren.
Ansonste, wie es für deinen Use-Case mit der 2. RegEx beim Watchdog funktionieren kann habe ich ja weiter oben schon geschrieben.
Bin an der Stelle leider raus.
Einfach hier lesen.
https://wiki.selfhtml.org/wiki/Perl/Regul%C3%A4re_Ausdr%C3%BCcke
LG
pah
RTFM? Einverstanden! :-[ ;)
Es dürfte etwas genauer wohl dieser Abschnitt sein:
https://wiki.selfhtml.org/wiki/Perl/Regul%C3%A4re_Ausdr%C3%BCcke#Assertions_.E2.80.93_Einbeziehung_des_Kontexts
und wenn ich es richtig verstanden habe, müsste der Ausdruck dann it etwa so enden:
(?!closed)
Nur die RegEx alleine ist nicht so schwierig; da findet man ja im Internet genug dazu, wie auch unter anderem den genannten Artikel. Wobei ich dennoch damit auf Kriegsfuß stehe; RegEx, genauso wie Perl, haben für mich eine unlogische Syntax. Anyways, ich wüsste nur gerne wie man es dann mit FHEM kombiniert. Wäre es dann TFKontaktEingang.(?!closed)
? Oder ohne Klammern, oder sonst irgendwie? Gebt doch mal ein simples Beispiel für eine RegEx in einem FHEM Kommando die nicht einen Standardstatus abfragt, sondern eben etwas mehr, wie z.B. verneint, oder mit mehr als nur .* am Ende arbeitet. Das wäre wesentlich einfacher, zweckdienlicher, weniger Aufwand für alle und daher schneller, als hier 3 Seiten mit Kommentaren zu füllen ...
Zitat von: MaxAut am 26 Juni 2016, 19:11:14
Das wäre wesentlich einfacher, zweckdienlicher, weniger Aufwand für alle und daher schneller, als hier 3 Seiten mit Kommentaren zu füllen ...
Na ja, du enthälst ja auch so einiges an Information zurück was du schon ausprobiert und gelesen hast.
Zitat von: MaxAut am 26 Juni 2016, 19:11:14
Nur die RegEx alleine ist nicht so schwierig; da findet man ja im Internet genug dazu, wie auch unter anderem den genannten Artikel.
TFKontaktEingang.(?!closed).*
sollte funktionieren.
ZitatGebt doch mal ein simples Beispiel für eine RegEx in einem FHEM Kommando die nicht einen Standardstatus abfragt, sondern eben etwas mehr, wie z.B. verneint, oder mit mehr als nur .* am Ende arbeitet. Das wäre wesentlich einfacher, zweckdienlicher, weniger Aufwand für alle und daher schneller, als hier 3 Seiten mit Kommentaren zu füllen ...
Das ist sicher nicht richtig.
ZitatRegEx, genauso wie Perl, haben für mich eine unlogische Syntax
Das ist noch weniger richtig. Reguläre Ausdrücke haben eine sehr klare mathematisch begründete Syntax, von "unlogisch" kann dabei ebenso wenig die Rede sein, wie bei der Syntax von Perl. Man muss sich halt mal selbst bemühen.
LG
pah
Danke Benni für das Beispiel! Endlich mal ein konkreter und brauchbarer Input! Zurückgehalten habe ich keine Informationen, jedenfalls nicht bewusst. In dem Thread habe ich mehrmals ganz genau geschrieben was ich machen möchte und was genau ich mit der RegEx abfragen möchte.
Eine Frage noch am Schluss: Wozu das .* am Ende? Warum ist TFKontaktEingang.(?!closed) nicht eindeutig?
.* muss nicht zwingend dahinter. Es steht für "und alles weitere, was folgt" (umgangsprachlich). Es kommt auf das Event an. Bitte mit der Materie tatsächlich beschäftigen. Man kann das ganze ja auch mal ausprobieren, wenn man sich nicht sicher ist.
BTW: Es ist nichts verkehrt daran, jemandem zu empfehlen, sich mit der Thematik auseinander zu setzen. Hier gibt es also ein klares Beispiel für den Missbrauch des unsäglichen Bewertungssystems. An Peter Hennings Aussage ist nichts falsch oder wenig hilfreich.
Für Anfänger bezüglich regulärer Ausdrücke halte ich das hier für sehr gelungen:
https://danielfett.de/de/tutorials/tutorial-regulare-ausdrucke/ (https://danielfett.de/de/tutorials/tutorial-regulare-ausdrucke/)
Und Peter Henning hat schon recht. Arbeitet man sich, wie empfohlen, in die Materie ein, sieht man sehr schnell dass reguläre Ausdrücke sehr wohl sehr logisch sind und man damit auch schnell zu Ergebnissen kommt. Die Empfehlung, sich damit zu beschäftigen führt dann sehr wohl zu kürzeren Threads, wenn die Leute der Empfehlung nachkommen.
Was .* bedeutet ist mir klar. Wäre meine Frage vollständig gelesen worden, hätte auch die Chance bestanden sie richtig zu verstehen: Ich wollte wissen warum .* am Ende notwendig ist, warum es ohne das nicht eindeutig gewesen wäre. Ich wollte NICHT wissen was .* grundsätzlich bedeutet.
Ein Missbrauch des Bewertungssystems? Spannend ... ist es nicht dazu da den persönlichen Gefallen an einer Antwort zum Ausdruck zu bringen? Für mich war PAH's Antwort unbrauchbar, und zudem wertend wo es nichts zu werten gab. Einen subjektiven Eindruck kann man nicht mit richtig oder falsch bewerten. Sollte es übrigens tatsächlich ein "Missbrauch" sein, so befinde ich mich zumindest in guter Gesellschaft, nachdem PAH meine Antwort mit der gleichen Bewertung versehen hat ;-).
ps: Kann dann bitte jemand diesen Thread schließen? Diese Diskussion ist unnötig. Danke.
Und wieder hat dir jemand einen hilfreichen Tipp gegeben und du schmeist ihn weg. So kommst du sicher vorwärts.
Wenn du dir das Event anschaust und dir klar darüber bist, was .* macht, kommst du darauf, warum es nötig ist. Ich bin nicht sicher, ob es hier nötig ist. Das findest du aber schnell heraus. Es ist für die Fälle (Events), in denen noch was folgt. Das kann auch ein Leerzeichen sein.
Du bist der Themenstarter. Also kannst du das Thema auch schließen. Sicher ist das nur sinnvoll, wenn du es auch vorher auf gelöst setzt (siehe angepinnte Beiträge).