FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: dk3572 am 23 Dezember 2020, 13:52:02

Titel: [Gelöst] If Bedingung in einer sub
Beitrag von: dk3572 am 23 Dezember 2020, 13:52:02
Hallo,

je nachdem wo Bewegung erkannt wurde, möchte ich auch dort die Sprachausgabe.
Hierfür rufe ich eine sub auf in der ich das cmd-event des DOIF auswerte.
Leider gibt es mir immer nur über das 1. if (BM_Wohnzimmer) die Sparche aus.

Ist jemand so nett und hilft mir auf die Sprünge?

Danke im Voraus und VG
Dieter

DEF        ([?Bewohner] eq "zuhause" && [?du_TTS:cnt] > 0 && ([BM_Wohnzimmer] eq "motion" or [BM_Kueche_Motion] eq "motion")) ({TTSSayQueue()}) DOELSE
   FUUID      5e3eed05-f33f-cd72-3f12-16920cbfa0495499
   FVERSION   98_DOIF.pm:0.234030/2020-12-22
   MODEL      FHEM
   NAME       di_TTSQueue
   NOTIFYDEV  BM_Wohnzimmer,BM_Kueche_Motion,global
   NR         350
   NTFY_ORDER 50-di_TTSQueue
   STATE      cmd_2
   TYPE       DOIF
   VERSION    23403 2020-12-22 15:43:36
   READINGS:
     2020-12-23 13:39:56   Device          BM_Wohnzimmer
     2020-12-23 13:39:56   cmd             2
     2020-12-23 13:39:56   cmd_event       BM_Wohnzimmer
     2020-12-23 13:39:56   cmd_nr          2
     2020-12-23 13:39:42   e_BM_Kueche_Motion_STATE nomotion
     2020-12-23 13:39:56   e_BM_Wohnzimmer_STATE nomotion
     2020-12-23 11:57:43   mode            enabled
     2020-12-23 13:39:56   state           cmd_2
   Regex:
     accu:
     cond:
       BM_Kueche_Motion:
         0:
           &STATE     ^BM_Kueche_Motion$
       BM_Wohnzimmer:
         0:
           &STATE     ^BM_Wohnzimmer$
   attr:
     cmdState:
     wait:
     waitdel:
   condition:
     0          ::InternalDoIf($hash,'Bewohner','STATE') eq "zuhause" && ::ReadingValDoIf($hash,'du_TTS','cnt') > 0 && (::InternalDoIf($hash,'BM_Wohnzimmer','STATE') eq "motion" or ::InternalDoIf($hash,'BM_Kueche_Motion','STATE') eq "motion")
   do:
     0:
       0          {TTSSayQueue()}
     1:
       0         
   helper:
     DEVFILTER  ^global$|^BM_Wohnzimmer$|^BM_Kueche_Motion$
     NOTIFYDEV  global|BM_Wohnzimmer|BM_Kueche_Motion
     event      nomotion,dark: 1
     globalinit 1
     last_timer 0
     sleeptimer -1
     timerdev   BM_Wohnzimmer
     timerevent nomotion,dark: 1
     triggerDev BM_Wohnzimmer
     DOIF_eventa:
       cmd_nr: 2
       cmd: 2
       cmd_event: BM_Wohnzimmer
       cmd_2
     DOIF_eventas:
       cmd_nr: 2
       cmd: 2
       cmd_event: BM_Wohnzimmer
       state: cmd_2
     timerevents:
       nomotion
       dark: 1
     timereventsState:
       state: nomotion
       dark: 1
     triggerEvents:
       nomotion
       dark: 1
     triggerEventsState:
       state: nomotion
       dark: 1
   internals:
     all         Bewohner:STATE BM_Wohnzimmer:STATE BM_Kueche_Motion:STATE
   readings:
   trigger:
   uiState:
   uiTable:
Attributes:
   DbLogExclude .*
   comment    DOIF steuert Ausgabe von Sprachnachrichten die vom Dummy du_TTS gesammelt werden.
Zugehörig 99_myTtsUtils.pm <sub TTSSayQueue()>
   do         always


sub TTSSayQueue() {
    my $text = '';
    my $cnt = ReadingsNum('du_TTS', 'cnt', 0);
    my $bm = ReadingsVal('di_TTSQueue', 'cmd_event', '');

    if ($cnt > 0) {

        for (my $i = 1; $i <= $cnt; $i++) {
            $text .= ReadingsVal('du_TTS', 'queue-' . $i, '') . '. ';
        }
   
    if ($bm eq "BM_Wohnzimmer"){
        fhem("set ECHO_G090LV03644201AX speak_ssml <speak>$text</speak>")}

    if ($bm eq "BM_Kueche_Motion"){
        fhem("set ECHO_G090P30874340EX4 speak_ssml <speak>$text</speak>")}

        fhem("deletereading du_TTS queue-.*");
        fhem("setreading du_TTS cnt 0");
    }
   
    return undef;
}
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 23 Dezember 2020, 14:23:40
Hi,

schreib doch einfach mal ins Log was da so an Werten drin steht in Deiner Sub
Log 1, "BM: $bm CNT: $cnt Text: $text";

Gruß Otto
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 23 Dezember 2020, 15:00:57
Hi,

danke für deine Unterstützung.

Es wird alles ausgewertet und übergeben, allerdings nur bei 2 Versuchen.
Danach wird immer nur noch BM_Wohnzimmer übergeben.

Kann es sein, dass das Reading des DOIF schneller übergeben wird als es gesetzt wird?

3 x hintereinander in Küche getestet, funktioniert.
1 x in Wohnzimmer getestet, funktioniert.
Wenn ich jetzt wieder Küche teste, wird im Wohnzimmer ausgegeben.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 23 Dezember 2020, 15:10:33
Sowas war auch meine Vermutung,... Ich sehe aber gerade:
Du fragst Zustände ab, ich würde gezielt auf den Event reagieren!

ich glaube so:
([BM_Wohnzimmer:"^motion"] or [BM_Kueche_Motion:"^motion"] )
oder sogar so:
["^BM_:^motion$"]
Triggert auf alle Geräte die mit BM:_ beginnen und auf genau den Event "motion"
da kein or auch keine Klammer :)

Und je länger ich darüber nachdenke, einfach ein notify mit BM und motion triggern, die beiden Readings in der Sub abfragen, $NAME beim Aufruf der Sub nutzen, da wird die Sub einfacher ;)
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 23 Dezember 2020, 15:37:56
Funktioniert leider nicht. Es muss aber wohl mit dem Bewegungsmelder Wohnzimmer und dem DOIF zusammen hängen.

Würdest du mir bei der sub mit deinem Vorschlag unter die Arme greifen?
Was meinst du mit $NAME nutzen?

Ich hätte mir jetzt mit z.B. my $bew = ReadinsVal von Bewohner geholt.
Der du_TTS cnt wird ja in der sub schon abgefragt und muss größer 0 sein.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Damian am 23 Dezember 2020, 16:27:45
Zitat von: dk3572 am 23 Dezember 2020, 15:37:56
Funktioniert leider nicht. Es muss aber wohl mit dem Bewegungsmelder Wohnzimmer und dem DOIF zusammen hängen.

Sollte aber. Erstens solltest du schauen, ob bei Bewegung motion-Events kommen - was ich mal unterstelle.

Deine Abfrage:

[BM_Wohnzimmer] eq "motion"

ist schon "gefährlich". Diese triggert bei jedem Event von BM_Wohnzimmer.

Ebenfalls die Auswertung von "internen" DOIF-Readings halte ich nicht für sinnvoll.

Dieser Einzeiler sollte schon ausreichen:

DOIF { if ([?Bewohner] eq "zuhause" and [?du_TTS:cnt] > 0 and ["^BM:motion"]) {::TTSSayQueue($device)}}

In TTSSayQueue kannst du den übergebenen Parameter unmittelbar auswerten, statt die Readings von DOIF.

Und wenn es nicht funktioniert, dann postest du am besten hier die Events der BMs.

Überholen kann sich da nichts.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 23 Dezember 2020, 16:42:13
Der Vorschlag von Damian ist hier Mist: ["^BM:motion"] triggert auch auf nomotion :( ich denke da ist  mein letzter Vorschlag aus #3 exakter
In deiner  Sub (nach Damians Vorschlag mit $device - entspricht meinem Vorschlag mit $NAME im notify)
so den Bewegungsmelder durch Übergabe haben:
sub TTSSayQueue($) {
my ($bm) = @_;
...
}
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 23 Dezember 2020, 18:55:38
Vielen Dank für eure Hilfe, aber was ist nun der bessere Weg?

Bei dem DOIF von Damian bekomme ich schon mal diesen Fehler:

error   condition c01: Too many arguments for main::TTSSayQueue,"

Wenn ich das Beispiel von Otto nehme,

([?Bewohner] eq "zuhause" && [?du_TTS:cnt] > 0 && ([BM_Wohnzimmer:"^motion"] or [BM_Kueche_Motion:"^motion"])) ({TTSSayQueue($NAME)}) DOELSE

wie baue ich das in der sub ein?
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 23 Dezember 2020, 19:52:39
Den Einzeiler von Damian habe ich nur teilweise verstanden, da kann ich zu dem Fehler nichts sagen.

Du nimmst nicht mein Beispiel, Du haust alles durcheinander  :-X
$NAME -> notify
$device -> DOIF

Wie Du den Parameter in die SUB einbaust habe ich doch geschrieben?
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 23 Dezember 2020, 21:59:25
sorry, habe mich vertan, du hast in der Tat das notify vorgeschlagen.
Leider bekomme ich dieses auch nicht hin.
Wenn ich es so versuche:

(BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*) {TTSSayQueue($NAME)}

erhalte ich diesen Fehler:

Too many arguments for main::TTSSayQueue at (eval 160856) line 1, near "$NAME)"

Wie muss das notify aussehen?
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 23 Dezember 2020, 22:03:43
Hast Du denn die Sub geändert?

Siehe #6

Wenn Du ein notify probieren willst musst Du in der Sub noch die Zusatz Bedingungen einfügen!
Der Trigger ist nicht falsch aber nicht gut. Die Klammern braucht es nicht
BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*
So ist es kürzer und ich denke der Event ist doch exakt motion?
BM_.*:motion
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 24 Dezember 2020, 09:08:53
Danke noch mal für deine Hilfe.

Ich möchte zuerst das notify anlegen.
Dann kümmere ich mich um die sub.
Eins nach dem Anderen  ;)

Deine Version von notify mag zwar kürzer sein, aber ich habe noch einige Bewegungsmelder mehr die mit BM_ anfangen.

Und wo und wie ich den $NAME einfüge weiß ich leider auch noch nicht.
Ich halte bei meiner Schreibweise immer die Fehlermeldung.

Vielleicht kannst du mir ja doch noch weiterhelfen?

Danke und ein schönes Weihnachtsfest.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Beta-User am 24 Dezember 2020, 09:19:16
Wirf' den prototype weg...
sub subname { 

[...] 
return;
}
@Otto: neben prototype könntest du eventuell mal shift+"defined-or" statt @_ vertiefen ;) 
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 24 Dezember 2020, 09:53:34
Notify sieht nun so aus:

(BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*) TTSSayQueue ($NAME)

Sub sieht so aus:

sub TTSSayQueue($) {
    my $text = '';
    my $cnt = ReadingsNum('du_TTS', 'cnt', 0);
    my ($bm) = @_;

    if ($cnt > 0) {

        for (my $i = 1; $i <= $cnt; $i++) {
            $text .= ReadingsVal('du_TTS', 'queue-' . $i, '') . '. ';
        }
   
    if ($bm eq "BM_Wohnzimmer"){
        fhem("set ECHO_G090LV03644201AX speak_ssml <speak>$text</speak>")}

    if ($bm eq "BM_Kueche_Motion"){
        fhem("set ECHO_G090P30874340EX4 speak_ssml <speak>$text</speak>")}

        fhem("deletereading du_TTS queue-.*");
        fhem("setreading du_TTS cnt 0");

    }
   
    return undef;
}


Steht folgende Warnung im Log:

PERL WARNING: Prototype mismatch: sub main::TTSSayQueue () vs ($) at ./FHEM/99_myTtsUtils.pm line 56

Ich lese mir hier im Forum viel an, studiere Wiki´s und probiere aus.
Leider bin ich kein Programierer und daher auf Hilfe angewiesen.
Ich bin auch dankbar für eure Mühe, aber die Andeutungen für die Ausführung helfen mir nicht weiter.

Mit Sicherheit ist es für euch Profis ein Klacks mein Anliegen umzusetzen.
Wäre also einer so nett und beschreibt etwas genauer wie das notify und wie die sub auszusehen hat?

Vielen lieben Dank dafür.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Beta-User am 24 Dezember 2020, 10:04:38
Wirf' den prototype GANZ raus und starte dann FHEM neu.

sub TTSSayQueue {
Titel: Antw:If Bedingung in einer sub
Beitrag von: Otto123 am 24 Dezember 2020, 10:14:43
Ach Mann, ich bin doch auch nicht der Profi mit Übergaben in einer Perlsub. Ich habe das mal vor langer Zeit so gemacht wie beschrieben, ja ich habe in der Perl Ecke mitgelesen - aber wie es jetzt richtig ist oder einfach nur geht ... ;)

Ich lese mich jetzt mal hier durch https://perldoc.perl.org/perlsub bis ich da fertig bin mache ich keine neuen Vorschläge zur Übernahme von übergebenen Werten {Sub($NAME)} 8)

@dk3572
Zumindest geht das Eine nicht ohne das Andere - Du kannst nicht einen Aufruf machen {Sub($NAME)} ohne in der Sub dann auch diesen Übergabewert irgendwie "aufzunehmen".
Daher der Fehler wie in #9 ;)


Das letzte notify ist Quark - so war mein Vorschlag - den hast Du in meiner nicht ausformulierten Aussage offenbar falsch verstanden:
BM_.*:motion {TTSSayQueue ($NAME)}

@Beta-User Wozu muss man wenn man die 99_myUtils editiert FHEM neu starten?
Titel: Antw:If Bedingung in einer sub
Beitrag von: dk3572 am 24 Dezember 2020, 11:15:22
ok, schwere Geburt, aber jetzt funktioniert es wie es soll.

(BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*) {TTSSayQueue ($NAME)}

Danke an alle und schöne Feiertage.

VG Dieter
Titel: Antw:[Gelöst] If Bedingung in einer sub
Beitrag von: Otto123 am 24 Dezember 2020, 12:51:42
Hallo Dieter,

Ich bleibe mal noch hartnäckig wegen der Klammer um das Suchmuster  8) und verlinke mal auf eine Diskussion. (https://forum.fhem.de/index.php?topic=115414.0)
Warum lässt Du die nicht weg?
(BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*)
funktioniert das so nicht?
BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*
Ist der Event nicht wirklich exakt motion? Wozu dann das "alles und Rest" hintendran .* ?
Funktioniert das nicht?
BM_Wohnzimmer:motion|BM_Kueche_Motion:motion

Noch zu meinem Link von oben, siehst Du den Unterschied wenn Du mal die beiden Ausdrücke getrennt in die Kommandozeile wirfst ?:
{notifyRegexpCheck('(BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*)')}
{notifyRegexpCheck('BM_Wohnzimmer:motion.*|BM_Kueche_Motion:motion.*')}

Auf alle Fälle Schöne Weihnachten!🎄

Otto
Titel: Antw:[Gelöst] If Bedingung in einer sub
Beitrag von: dk3572 am 24 Dezember 2020, 13:17:08
alles klar, habe es so abgeändert, funktioniert auch.

BM_Wohnzimmer:motion|BM_Kueche_Motion:motion {TTSSayQueue ($NAME)}


Danke nochmal.
Titel: Antw:If Bedingung in einer sub
Beitrag von: Beta-User am 24 Dezember 2020, 13:36:30
Zitat von: Otto123 link=topic=117006.msg1113869#msg1113869
@Beta-User Wozu muss man wenn man die 99_myUtils editiert FHEM neu starten?
Das betrifft NUR den Fall, dass man was an Funktionen ändert, die mit prototype arbeiten und auch nur dann, wenn sich der prototype ändert; (jedenfalls hatte ich das mal irgendwo so aufgeschnappt).

Sonst funktioniert das Editieren von myUtils via FHEMWEB stressfrei, keine Sorge ;) .

HIER war es aber vermutlich der Grund, warum es erst nicht funktioniert hat beim Wechseln von () nach ($), was mich in dem Bauchgefühl bestätigt, dass PBP Recht damit hat, dass man im Zweifel lieber auf prototype verzichten sollte.

Und wenn meine Zwischenbemerkung zum Thema shift war nicht böse gemeint, man kann auch die @_-Variante nutzen (war nur, weil ich grade sowieso dabei war wg. dieser prototype-Geschichte). In "meinen" Modulen flog das aber fast überall raus zugunsten der shift-Schreibweise; die erlaubt es m.E. eleganter, gleich Ersatzwerte oder qualifizierte Rückgaben/Fehlermeldungen reinzubauen. Dann bekommt man statt "prototype missmatch" eben "we need a target device as argument" oder "you have to specify a target value" zurück oder kann was ins Log schreiben etc....
Bin sicher, du hast das mit dem Perl-"defined-or" ("//") binnen 15 Minuten intus :) .