Ankündigung

Einklappen
Keine Ankündigung bisher.

Decoder Plugin zum Haustüröffnen etc.

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    [wiregate] Decoder Plugin zum Haustüröffnen etc.

    Ich habe hier mal die Betaversion eines Decoderplugins.

    Dss Plugin kann Tastendrücke auswerten und je nach 'eingetastetem' Code unterschiedliche Aktionen ausfuehren. Wer außen am Haus einen Taster mit einem Binaereingang verbindet., oder einen sonstigen EIB-Taster zur Verfügung hat, kann damit z.B seine Haustuer oeffnen.

    Es ist aber auch möglich, auf bestimmte Abfolgen von Ereignissen zu reagieren, die sich z.B. ueber einen längeren Zeitraum hinziehen, wenn die entsprechenden Timeouts im Script angepasst werden.

    Die verwendeten Taster können gefahrlos weiter im Normalbetrieb verwendet werden, da das Plugin Einzeleingaben erkennt und ausfiltert.

    Von einem Taster aus können beliebig viele, unterschiedliche Codes erkannt werden, und entsprechend unterschiedliche Aktionen ausgelöst werden. Für jeden Code können andererseits aber auch beliebig viele Aktionen hintereinander ausgeführt werden.

    Die Eingaben können auf bestimmte physische Adressen beschränkt werden, so dass eine GA auf dem Bus nur dann zu einer Reaktion führt, wenn sie vom beabsichtigten, physischen Gerät stammt. Man kann die Eingabe aber auch von allen Geräten aus zulassen, die die fragliche GA versenden können.

    Bei einer oder mehrerer Falscheingaben wird die Dekoderfunktion blockiert. Die Anzahl Fehlversuche, die anfängliche Blockadezeit und die maximale Blockadezeit sind einstellbar. Mit jeder weiteren Falscheingabe verdoppelt sich die Blockadezeit.

    Aktuell sind eingestellt:

    Code:
    [FONT="Courier New"]
    my $pauseSec       = 1.0;  # Pausenzeit, nach der eine Ziffer komplett ist
    my $completeAfter  = 4;    # Wartezeit in Sekunden, nach der der Code ausgewertet wird
    my $maxFails       = 3;    # Anzahl Fehlversuche
    my $blockPeriod    = 30;   # anfaengliche Blockadezeit in Sekunden.
    my $maxBlockPeriod = 3600; # maximale Blockadezeit[/FONT]
    Wichtig sind dabei $pauseSec und $completeAfter.

    $pauseSec gibt die Zeit an, nach der eine Ziffer als vollständig angesehen wird.
    $completeAfter gibt die Zeit an, nach der der gesamte Code als vollständig angesehen wird.

    Beispiel:

    - Taster wird drei mal kurz hintereinander gedrueckt
    - kurze Pause
    - Taster wird vier mal kurz hintereinander gedrueckt
    - kurze Pause
    - Taster wird fuenf mal kurz hintereinander gedrueckt

    wird dekodiert zu '345'. 10 Tastendrücke entsprechen einer '0', mehr als 10 Tastendrücke werden als Falscheingabe gewertet.

    Tests bei mir haben ganz gut funktioniert. Die gewählten Timings sind für mich jedenfalls gut handhabbar.

    Hier das Script, es ist Beta. Wenn es allgemein als OK angesehen wird, stelle ich es in SVN.
    Code:
    [FONT="Courier New"]# Plugin zur Erkennung eines Tastencodes
    # License: GPL (v2)
    # version von emax
    #
    # Das Plugin analysiert die Ereignisse einer gegebenen GA, und wertet die 
    # Zeitabstaende zwischen den Telegrammen aus. Je nach erkanntem Muster wird 
    # eine vorgegebene Funktion ausgefuehrt.
    #
    # Das Plugin ist z.B. als Notbehelf im Falle einer zugefallen Haustuer 
    # gedacht.
    #
    # Funktionsweise:
    # ---------------
    # Mit jedem erkannten Tastendruck wird ein Zaehler inkrementiert, sofern der 
    # letzte Tastendruck der betreffenden GA nicht laenger her ist als eine Sekunde
    # (einstellbar). Wird eine Pause von mehr als einer Sekunde erkannt, wird 
    # der Wert des Zaehlers gespeichert, und der Zaehler auf Null gesetzt.
    # Entsprechen die so gesammelten Werte einem bestimmten Code, wird eine 
    # vorgegebene Funktion ausgefuehrt.
    #
    # Auf diese Weise laesst sich jeder Lichtschalter z.B. als Tueroeffner 
    # verwenden, wenn er in einem bestimmten Muster gedrueckt wird.
    #
    # Beispiel:
    # - Taster wird drei mal kurz hintereinander gedrueckt
    # - ueber eine Sekunde Pause
    # - Taster wird vier mal kurz hintereinander gedrueckt
    # - ueber eine Sekunde Pause
    # - Taster wird fuenf mal kurz hintereinander gedrueckt
    # - ueber eine Sekunde Pause
    #
    # wird dekodiert zu '345'. 10 Tastendruecke entsprechen einer '0', mehr als 10 
    # Tastendruecke werden als Falscheingabe gewertet.
    #
    # Wird eine Pause von mehr als vier (einstellbar) Sekunden gemacht, wird der 
    # Code als vollstaendig angesehen und ausgewertet. Nach der Auswertung werden 
    # alle Zaehler wieder auf Null gesetzt, und von vorne begonnen.
    #
    # Nach drei Falscheingaben (einstellbar) wird die Auswertung fuer eine Minute 
    # (einstellbar) blockiert. Nach jeder weiteren Falscheingabe verdoppelt sich 
    # die Blockadezeit.
    #
    # Die GA kann weiterhin fuer andere Aufgaben verwendet werden, da das Script 
    # nur zusammenhaengenede Eingaben auswertet, und Einzeleingaben ignoriert.
    
    #-----------------------------------------------------------------------------
    # Einstellungen
    #-----------------------------------------------------------------------------
    
    my $oneDay         = (24 * 3600);
    my $pauseSec       = 1.0;  # Pausenzeit, nach der eine Ziffer komplett ist
    my $completeAfter  = 4;    # Wartezeit in Sekunden, nach der der Code ausgewertet wird
    my $maxFails       = 3;    # Anzahl Fehlversuche
    my $blockPeriod    = 30;   # anfaengliche Blockadezeit in Sekunden.
    my $maxBlockPeriod = 3600; # maximale Blockadezeit
    
    #-----------------------------------------------------------------------------
    # - Es koennen beliebig viele Eintraege fuer ein und den selben Code gemacht 
    #   werden, sie werden alle ausgefuehrt.
    # - Wird ein 'FromPA' Wert angegeben, wird der Code nur von dieser PA akzeptiert.
    # - 'FromGA' und 'ToGA' duerfen nicht identisch sein.
    # - Der Code darf nur aus Ziffern bestehen, muss aber in Hochkommas angegeben 
    #   werden. So gehen auch fuehrende Nullen. Zehn Tastendruecke sind eine Null.
    #-----------------------------------------------------------------------------
    my @Codes =
        (
         { Active=>1, Code=>'123',FromGA=>'1/1/121', FromPA=>undef, Value=>'1', DPT=>'1', ToGA=>'1/1/123', Log=>'1' },
         { Active=>1, Code=>'123',FromGA=>'1/1/121', FromPA=>undef, Value=>'1', DPT=>'1', ToGA=>'3/2/1',   Log=>'1' },
         { Active=>1, Code=>'321',FromGA=>'1/1/121', FromPA=>undef, Value=>'0', DPT=>'1', ToGA=>'1/1/123', Log=>'1' },
         { Active=>1, Code=>'456',FromGA=>'1/1/121', FromPA=>undef, Value=>'1', DPT=>'1', ToGA=>'1/1/121', Log=>'1' },
        );
    
    #-----------------------------------------------------------------------------
    # ACHTUNG: die Versionsnummer IMMER veraendern, wenn das script geaendert wurde.
    # Der Wert muss numerisch sein, egal ob hoeher oder niedriger als die
    # Vorversion. Es ist auch egal, ob die Version bereits verwendet wurde,
    # es kommt nur darauf an, das der Wert ANDERS ist als zuvor.
    #-----------------------------------------------------------------------------
    my $version = 1;
    
    #-----------------------------------------------------------------------------
    # ENDE Einstellungen
    #-----------------------------------------------------------------------------
    
    use POSIX;
    my $dbg = ':dJ:'; # ':ALL:dSS:dWS:dBS:state:code:cycle:counter:msg:cC:dJ:'; # ALL:alles, 
    my %varInit =  (initialized=>1, lastRun=>0, blockEnd=>0, curBlockPeriod=>0, curCode=>'', fails=>0, state=>'sleeping');
    my ($seconds, $uSec, $tStamp, $state, $lastRun, $dTime, $piPrefix, $minCodeLength);
    
    sub debug()
    {
        my ($tag, $text) = (@_);
        my $caller = (caller(1))[3];
        ($dbg =~ /:ALL:|$tag/) and plugin_log($plugname, "DBG$tag$caller:"."$text");
        return 1;
    } # debug()
    
    sub doInit
    {
        &debug(':DFR:', 'entering');
    
        # Kontrollierte Startkonditionen setzen
        # Die Funktion wird aufgerufen, wenn es der erste Lauf einer Plugin-Version 
        # ist. Es werden alle Werte aus alten Versionen aus %plugin_info geloescht. 
        # "$plugname.$version.initialized" wird gesetzt, und auch alle anderen
        # kuenftig verwendeten plugin_info-Variablen angelegt.
    
        plugin_log($plugname, "Starting plugin version $version.");
    
        # obsolete Versionen von $plugin_info bereinigen
        foreach (keys %plugin_info)
        {
            if (/^$plugname\.\d+\./)
            {
                delete $plugin_info{$_};
                plugin_log($plugname, "deleted obsolete plugin_info[$_]");
            }
        }
    
        # Variablen zuruecksetzen
        &reset();
    
        # Die minimale Codelaenge wird unten ermittelt. 
        # Kuerzere Codes werden verworfen.
        $minCodeLength = 999; 
    
        foreach my $code (@Codes)
        {
            if (defined $code->{FromGA})
            {
                if (defined $code->{FromGA} && defined $code->{ToGA} &&
                    $code->{FromGA} eq $code->{ToGA})
                {
                    plugin_log($plugname, "ERROR: source GA[$code->{FromGA}]and destination GA[$code->{FromGA}] are the same, entry ignored.");
                    next;
                }
    
                my $GA = $code->{FromGA};
    
                if (defined $code->{Active} &&
                    $code->{Active} == 1)
                {
                    plugin_log($plugname, "subscribing to GA[$GA]");
                    $plugin_subscribe{$GA}{$plugname} = 1;
    
                    # Ermitteln der minimalen Code-laenge. 
                    # Alle codes, die kuerzer sind, werden ignoriert,
                    # und fuehren auch nicht zu Fehlern.                
                    (length($code->{Code}) < $minCodeLength) and $minCodeLength = length($code->{Code});                 
                }
                elsif (exists $plugin_subscribe{$GA}{$plugname})
                {
                    plugin_log($plugname, "deleting obsolete subscription to GA[$GA]");
                    delete $plugin_subscribe{$GA}{$plugname};
                }
            } # defined FromGA
        } # each $code
    
        $plugin_info{"$piPrefix.minCodeLength"} = $minCodeLength;
            
        # debug
        if ($dbg =~/:ALL:|:dFR:/) 
        {
            foreach (keys %plugin_subscribe)
            {
                &debug(':DFR:', "pluginSubscribeKey[$_]");
            }
        } # debug     
        $plugin_info{$plugname.'_cycle'} = $oneDay;
    } # doFirstFRun
    
    sub setBlockingPeriod()
    {
        &debug(":sBT:", "entering");
        my $fails = $plugin_info{"$piPrefix.fails"} + 1;
        plugin_log($plugname, "invalid code #[$fails]");
        $plugin_info{"$piPrefix.fails"} = $fails;
        if ($fails >= $maxFails)
        {
            my $curBlockPeriod = $plugin_info{"$piPrefix.curBlockPeriod"};
            my $newBlockPeriod = ($curBlockPeriod == 0) ? $blockPeriod : $curBlockPeriod + $curBlockPeriod;
            ($newBlockPeriod > $maxBlockPeriod) and $newBlockPeriod = $maxBlockPeriod;
            plugin_log($plugname, "setting blocking period for GA[".$plugin_info{"$piPrefix.GA"}.
                       " from [$curBlockPeriod] sec to [$newBlockPeriod] sec");
            $plugin_info{"$piPrefix.curBlockPeriod"} = $newBlockPeriod;        
            $plugin_info{"$piPrefix.blockEnd"} = $tStamp + $newBlockPeriod;
            $plugin_info{"$piPrefix.state"} = 'blocked';
            ($plugin_info{"$plugname".'_cycle'} < $newBlockPeriod) and $plugin_info{"$plugname".'_cycle'} = $newBlockPeriod;
        }
        else 
        { 
            # Wenn die maximale Anzahl Fehleingaben noch nicht erreicht wurde,
            # werden diese Variablen zurueckgesetzt.
            $plugin_info{"$piPrefix.curCode"} = '';
            $plugin_info{"$piPrefix.state"} = 'sleeping';
            $plugin_info{"$plugname".'_cycle'} = $oneDay;        
       }
    } # setBlockingPeriod
    
    sub checkCode()
    {
        &debug(':cC:', 'entering');
        # Es werden alle %Codes Eintraege auf einen passenden code ueberprueft.
        # Da meherere Codes je GA verarbeitet werden koennen, ist der Eintrag 
        # abhaengig von
        # - sendender GA
        # - ermitteltem Code
        # Wenn diese beiden Werte uebereinstimmen, wird der %Codes-Eintrag zurueckgegeben.
        # Stimmt kein Eintrag ueberein, wird 'undef' zurueckgegeben.
    
        my $curCode = $plugin_info{"$piPrefix.curCode"};
        &debug(':cC:', "curCode[$curCode]");
        my $idx = -1;
        foreach my $code (@Codes)
        {
            ++$idx;
            if (defined $code->{FromGA} && defined $code->{ToGA} &&
                $code->{FromGA} eq $code->{ToGA})
            {
                plugin_log($plugname, "ERROR: source GA[$code->{FromGA}]and destination GA[$code->{FromGA}] are the same, entry ignored.");
                next;
            }
    
            (!defined $code->{Active} || !$code->{Active}) and 
                &debug("cC:", "not Active") and next;
            (!defined $code->{Code} ||    $code->{Code} ne $plugin_info{"$piPrefix.curCode"}) 
                and &debug("cC:", "no Code") and next;
            (!defined $code->{FromGA} ||  $code->{FromGA} ne $plugin_info{"$piPrefix.GA"}) 
                and &debug("cC:", "not FromGA")and next;
            (defined $code->{FromPA} &&  $code->{FromPA} ne $plugin_info{"$piPrefix.PA"}) 
                and &debug("cC:", "not FromPA")and next;
            &debug(':cC:', "found Code[$curCode]");
            return $idx;
        }
        return undef;
    }
    
    sub doJob()
    {
        &debug(':dJ:', 'entering');
        my $codeIdx = shift;
        my $codeCount = @Codes;
    
        &debug(":dJ:", "codeCount[$codeCount]");
        
        # Hier werden alle %Codes ausgefuehrt, die den aktuellen parametern entsprechen.
        # Es koennen hinterainander mehrere Kommandos fuer den gleichen Code ausfuehrt
        # werden. Ebenso unterschiedliche Kommandos vom gleichenm Taster, je nach Code.
    
        for (; $codeIdx < $codeCount; ++$codeIdx)
        {
            # es werden alle Eintraege verarbeitet, die dem Filter entsprechen
            my $code = $Codes[$codeIdx];
            (!defined $code->{Active} || !$code->{Active}) and next;
            (!defined $code->{Code} ||    $code->{Code} ne $plugin_info{"$piPrefix.curCode"}) and next;
            (!defined $code->{FromGA} ||  $code->{FromGA} ne $plugin_info{"$piPrefix.GA"}) and next;
            (defined $code->{FromPA} &&  $code->{FromPA} ne $plugin_info{"$piPrefix.PA"}) and next;
            (defined $code->{Log} && $code->{Log}) and 
                plugin_log($plugname, 'executing from PA['.$plugin_info{"$piPrefix.PA"}.
                           '] From GA['.$plugin_info{"$piPrefix.GA"}.
                           '], sending ['.$code->{Value}.
                           '] to  ['.$code->{ToGA}.'].');
            knx_write($code->{ToGA},$code->{Value}, $code->{DPT});
        }
    } # doJob
    
    sub reset()
    {
        &debug(':RES:', 'entering');
        # Alle Variablen und '$state' zuruecksetzen
        foreach (keys %varInit)
        {
            &debug(':RES:',"(re)setting [$piPrefix.$_] to [$varInit{$_}]");
    	$plugin_info{"$piPrefix.$_"} = $varInit{$_} 
        }
    
        $plugin_info{"$plugname".'_cycle'} = $oneDay;
    } # reset()
    
    sub doSleepingState()
    {
        &debug(':dSS:', 'entering');
        $plugin_info{"$piPrefix.lastRun"} = $tStamp;
    
        # Wird ausgefuehrt, wenn das Plugin das erste Mal getriggert wird nach
        # - der Initialisierung
        # - einem vollstaendigen Code oder
        # - dem Status 'blocked'
    
        # Wenn keine GA geliefert wurde, geschah der Aufruf aufgrund eines _cycle Timeouts.
        # Dann ist nichts weiter zu tun.
        if (!defined $msg{'dst'}) 
        {
            # refresh _cycle
            $plugin_info{"$plugname".'_cycle'} = $oneDay;
            return;
        };
    
        &debug(':dSS:', 'setting GA/PA filters');
    
        # GA & PA merken.
        # Bis der Code vollstaendig ist, werden nur noch Telegramme dieser GA und von 
        # dieser PA ausgwertet. Alle anderen telegramme werden so lange ingnoriert.
        $plugin_info{"$piPrefix.GA"} = $msg{'dst'};
        $plugin_info{"$piPrefix.PA"} = $msg{'src'};
        $plugin_info{"$piPrefix.counter"} = 1;
        $plugin_info{"$piPrefix.curCode"} = '';
        $plugin_info{"$plugname".'_cycle'} = $completeAfter;
        $plugin_info{"$piPrefix.state"} = 'waiting';
    } # doSleepingState
    
    sub doWaitingState()
    {
        &debug(':dWS:', 'entering');
        
        # errechne abgelaufene Zeit
        $lastRun =  $plugin_info{"$piPrefix.lastRun"};
        $dTime = $tStamp - $lastRun;
        &debug(':dWS:', "dTime[$dTime]");
    
        if (!defined $msg{'dst'})
        {
            &debug(':dWS:', 'no GA');
            if ($dTime < $pauseSec)
            {
                # Aus einem mir unbekannten Grunde passiert es, dass
                # das Script aufgerufen wird, ohne das eine GA geliefert wird,
                # obwohl kein _cycle Timeout stattfand.
                # Solche Ereignisse werden ignoriert.
                return;
            }
    
            $plugin_info{"$piPrefix.lastRun"} = $tStamp;
    
            # Keine GA, aber _cycle Timeout
            # Wenn es zwischenzeitlich Tastendruecke stattfanden, 
            # diese zum Code inzufuegen.
            if ($plugin_info{"$piPrefix.counter"})
            {
                ($plugin_info{"$piPrefix.counter"} == 10) and $plugin_info{"$piPrefix.counter"} = 0;
                $plugin_info{"$piPrefix.curCode"} .= $plugin_info{"$piPrefix.counter"};
                $plugin_info{"$piPrefix.counter"} = 0;
                plugin_log($plugname, 'current code['.$plugin_info{"$piPrefix.curCode"}.']');
            }
    
            &debug(':dWS:', "curCode[".$plugin_info{"$piPrefix.curCode"}.']');
            if (length($plugin_info{"$piPrefix.curCode"} < $minCodeLength))
            {
                plugin_log($plugname, 'code too short, discarded.');
                &reset();
                return;
            }
    
            my $codeIdx = &checkCode();
            if (defined $codeIdx)
            {
                &debug(':dWS:', 'code ok');
                &doJob($codeIdx);
                &reset();
            }
            else
            {
                &debug(':dWS:', 'code not ok');
                &setBlockingPeriod();
            }
            return;
        } # ... no GA 
    
        $plugin_info{"$piPrefix.lastRun"} = $tStamp;
    
        # Ein GA-Event
        # Ausfiltern, sofern nicht die aktuelle GA oder nicht von der gleichen PA
        if ($msg{'dst'} ne $plugin_info{"$piPrefix.GA"} ||
            $msg{'src'} ne $plugin_info{"$piPrefix.PA"})
        {
            # Das Event wird ignoriert.
            # verwrfen, und neue _cycle zeit ausrechnen, damit der naechste Aufruf zum 
            # (halbwegs) richtigen Zeitpunkt stattfindet.
            $plugin_info{$plugname.'_cycle'} = $completeAfter - $dTime;
            return;
        }
    
        # Das Ereignis kam von 'unserer' Quelle und ist fuer 'unsere Zieladresse.
        if ($dTime < $pauseSec)
        {
            if ($plugin_info{"$piPrefix.counter"} == 10)
            {
                # error
                &debug(':dWS:', "counter too big[".$plugin_info{"$piPrefix.counter"}.']');
                &setBlockingPeriod();
            }
            else
            { 
                ++$plugin_info{"$piPrefix.counter"};
            }
            return;
        }
        else       # Pause entdeckt
        {
            &debug(':dWS:', 'pause detected, counter is '.$plugin_info{"$piPrefix.counter"});
            # sofern zwischenzeitlich Ereignisse gezaehlt wurde, diese dem Code 
            # hinzufuegen und den Zaehler zuruecksetzen.
            if ($plugin_info{"$piPrefix.counter"})
            {
                &debug(':dWS:', "assembling code");
                ($plugin_info{"$piPrefix.counter"} == 10) and $plugin_info{"$piPrefix.counter"} = 0;
                $plugin_info{"$piPrefix.curCode"} .= $plugin_info{"$piPrefix.counter"};
                plugin_log($plugname, 'current code['.$plugin_info{"$piPrefix.curCode"}.']');
            }
            $plugin_info{"$piPrefix.counter"} = 1;
            &debug(':dWS:', "after pause curCode[".$plugin_info{"$piPrefix.curCode"}.']');
        }
    } # doWaitingState
    
    sub doBlockedState()
    {
        &debug(':dBS:', 'entering');
        $plugin_info{"$piPrefix.lastRun"} = $tStamp;
    
        if ($tStamp >= $plugin_info{"$piPrefix.blockEnd"})
        {
            plugin_log($plugname, 'blocking time expired, going to sleep');
            &debug(':dBS:', 'blocking time expired, resetting block');
            $plugin_info{"$piPrefix.curCode"} = '';
            $plugin_info{"$piPrefix.state"} = 'sleeping';
            $plugin_info{"$plugname".'_cycle'} = $oneDay;
        }
    } # doBlockedState
    
    #=============================================================================
    # main() 
    #=============================================================================
    
    ($seconds,$uSec) = gettimeofday();
    $tStamp = $seconds + $uSec/1000000; 
    $lastRun = 0;
    $piPrefix = "$plugname.$version";
    
    my $oldCycleTime = $plugin_info{"$plugname".'_cycle'};
    $minCodeLength = $plugin_info{"$piPrefix.minCodeLength"};
    
    # ggf. neue Version initialiseren
    if (!defined $plugin_info{"$piPrefix.initialized"})
    {
        &doInit();
        return;
    }
    
    $state = $plugin_info{"$piPrefix.state"};
    &debug(':state:', "on entry state[$state]");
    
    &debug(':msg:', "msg debug -------------");
    &debug(':msg:', "msg[$_]=$msg{$_}") foreach (keys %msg);
    &debug(':msg:', "/msg debug ------------");
    
    if    ($state eq 'sleeping') { &doSleepingState(); } 
    elsif ($state eq 'waiting')  { &doWaitingState();  }
    elsif ($state eq 'blocked')  { &doBlockedState();  }
    else { 
        plugin_log($plugname, "FATAL: unknown state[$state], resetting");
        &doInit();
    }
    
    &debug(':state:',   "on exit state[".$plugin_info{"$piPrefix.state"}.']');
    &debug(':counter:', "on exit counter[".$plugin_info{"$piPrefix.counter"}.']');
    &debug(':code:',    "on exit code[".$plugin_info{"$piPrefix.curCode"}.']');
    &debug(':cycle:',   "on exit cycle[".$plugin_info{"$plugname".'_cycle'}.']');
    
    ($oldCycleTime != $plugin_info{"$plugname".'_cycle'}) and 
        plugin_log($plugname, 'cycle time set to '.$plugin_info{"$plugname".'_cycle'}.' seconds');
    [/FONT]
    Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

    #2
    Ich habe hier noch ein Beispiel für eine andere Art der Anwendung:

    Code:
    [FONT="Courier New"]
    
    my @Codes =
        (
         # Ein mal tasten: Esstisch an
         { Active=>1, Code=>'1',FromGA=>'1/1/121', Value=>'1', DPT=>'1', ToGA=>'3/2/1', Log=>'1' },
    
         # Zwei mal tasten, Esstisch aus, Fernsehlicht an
         { Active=>1, Code=>'2',FromGA=>'1/1/121', Value=>'0', DPT=>'1', ToGA=>'3/2/1', Log=>'1' },
         { Active=>1, Code=>'2',FromGA=>'1/1/121', Value=>'1', DPT=>'1', ToGA=>'3/2/2', Log=>'1' },
    
         # Drei mal tasten: Esstisch an, Fernsehlicht an, Wohnzimmerdecke an
         { Active=>1, Code=>'3',FromGA=>'1/1/121', Value=>'1', DPT=>'1', ToGA=>'3/2/1', Log=>'1' },
         { Active=>1, Code=>'3',FromGA=>'1/1/121', Value=>'1', DPT=>'1', ToGA=>'3/2/2', Log=>'1' },
         { Active=>1, Code=>'3',FromGA=>'1/1/121', Value=>'1', DPT=>'1', ToGA=>'3/2/3', Log=>'1' },
    
         # Ein mal, dann zwei mal tasten: Alles aus
         { Active=>1, Code=>'12',FromGA=>'1/1/121', Value=>'0', DPT=>'1', ToGA=>'3/2/1', Log=>'1' },
         { Active=>1, Code=>'12',FromGA=>'1/1/121', Value=>'0', DPT=>'1', ToGA=>'3/2/2', Log=>'1' },
         { Active=>1, Code=>'12',FromGA=>'1/1/121', Value=>'0', DPT=>'1', ToGA=>'3/2/3', Log=>'1' },
        );[/font]
    In diesem Beispiel dient ein Taster für unterschiedliche Aufgaben: Je nach Tastmuster schaltet ein Schalter unterschiedliche Szenen, wie im Code kommentiert. Es gibt mehr Möglichkeiten als zunächst gedacht. Da auch andere DPTn gesendet werden können, lassen sich natürlich auch Dimmszenen schalten.

    Ein paar Ideen habe ich noch:
    • eine Werterkennung, also unterschiedliche Aktionen für 'ein' oder 'aus' Telegramme.
    • 'Toggle' Aktionen ermöglichen, also Funktion 'umschalten'.
    • Delays. D.h.: Verzögerte Aktionen: Sekunden, Minuten, Stunden ...


    Die Delays sind erst mal eine wilde Idee, es wäre schon etwas Gefrickel, das zu implementieren.
    Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

    Kommentar


      #3
      Das ist ja mal eine interessante Sache....

      Danke!

      Kommentar


        #4
        Zitat von division Beitrag anzeigen
        Das ist ja mal eine interessante Sache....
        Das finde ich auch !

        Kommentar


          #5
          Mit freundlichen Grüßen
          Niko Will

          Logiken und Schnittstelle zu anderen Systemen: smarthome.py - Visualisierung: smartVISU
          - Gira TS3 - iPhone & iPad - Mobotix T24 - ekey - Denon 2313 - Russound C5 (RIO over TCP Plugin) -

          Kommentar


            #6
            Nerds stellen dann noch auf Morsecode um.
            Derzeit zwischen Kistenauspacken und Garten anlegen.
            Baublog im Profil.

            Kommentar


              #7
              Danke für die positiven Reaktionen. Interessant wären Tests und Anwendungen. Als Entwickler hat man hinsichtlich der Verwendbarkeit ja immer eine etwas geschönte Sicht. Deshalb bin ich neugierig, wie andere die Verwendbarkeit einschätzen. Es ist sehr stark von den eingestellten Timings abhängig.

              Je 'zahmer' (also länger) die Intervalle eingestellt sind, desto einfacher die Handhabung - aber dafür auch desto träger die Reaktion.


              Zitat von greentux Beitrag anzeigen
              Nerds stellen dann noch auf Morsecode um.
              Wenn die Auswertung der Telegrammdaten 0/1 mal implementiert ist, wäre auch das kein Problem mehr.

              Aber wozu ? :-)
              Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

              Kommentar


                #8
                Ob ich nun 9 mal drücke für die 9 oder eben eine 9 morse, macht einen Unterschied. Die 9 braucht nur 5 Zeichen, nur 3 in de rkurzen Version...

                Es gibt doch Taster die können Drücken und Loslassen unterscheiden. Damit kann man dann richtig morsen. Also lang und kurz unterscheiden...
                Derzeit zwischen Kistenauspacken und Garten anlegen.
                Baublog im Profil.

                Kommentar


                  #9
                  Ich weiss. Jede Morseziffer braucht nur fünf Zeichen. Aber wer kennt schon das Morsealphabet ...

                  Aber ob man es nun Morsen nennt oder schlicht binär, das Prinzip habe ich per 0/1 Datenerkennung ja bereits in der Mache. Denn tatsächlich ist ein Muster wie z.B. '0110111' viel schneller getippt.

                  Das Problem ist nur, dass man den Taster dann nicht mehr so ohne weiteres für 'normale" Aufgaben verwenden kann - würde doch der Nachbar am Ein/Aus Rythmus der zugehörigen Lampe wunderbar erkennen, was man da gerade eintippt ...
                  Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

                  Kommentar


                    #10
                    Steht ab jetzt auch im svn, vorerst so wie vorgestellt. Binaerversion folgt eventuell später.

                    Wie immer gilt: Erst mal bitte testen, man kann beim Einstellen ins svn immer mal was übersehen.
                    Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

                    Kommentar


                      #11
                      Hallo Emax,

                      danke für das Plugin. Ich möchte es nutzten um meinem superteuren Taster, der leider nix kann (B.IQ Komfort) etwas auf die Sprünge zu helfen.

                      Dazu bräuchte ich allerdings die Toggle-Funktion. Die hast du nicht zufällig schon implementiert, oder? (Im SVN habe ich nix gesehen, aber manchmal hat man ja eine aktuellere Version daheim).

                      Gruß,
                      Hendrik

                      Kommentar


                        #12
                        Servus,

                        nein, ich habe seit langem kaum Zeit mich um sowas zu kümmern. Würde ich aber gerne ... :-)

                        Wenn Du in diesem Thread Mitte November noch mal anfragst dürfte das nicht schaden, vielleicht klappt es dann.
                        Kein Support per PN: Fragen bzw. Fehlermeldungen bitte im Forum posten.

                        Kommentar


                          #13
                          Hehe.. Woher kenn ich das ?!

                          Ich werd auf dich zurückkommen!

                          Kommentar


                            #14
                            Hallo nochmal,

                            vielleicht geht das ja auch schon ohne die Toggle-Funktion.
                            Ich beschreibe mal, was ich vor habe:
                            Einfacher Tastendruck: Toggle ein/aus (1/1/1)
                            Doppelter Tastendruck: Automatik-Modus ein (1/1/2)

                            Der Status von 1/1/2 soll auf der LED angezeigt werden.

                            Variante 1)
                            Jetzt könnte ich die 1/1/2 dem Taster zuweisen und vom Decoder einfach/zweifach auswerten lassen. Der sendet dann eben auf die 1/1/1 oder auf die 1/1/2. So wird auch der Status angezeigt.

                            Allerdings funktioniert so das "Toggle" nicht.

                            Variante 2)
                            Jetzt könnte ich die 1/1/1 dem Taster zuweisen und vom Decoder zweifach (einfach klappt ja schon per se und auch mit toggle) auswerten lassen. Der sendet dann eben auf die 1/1/2. So wird auch der Status aber nicht angezeigt, da die LED ja nur auf den Status von 1/1/1 lauscht.

                            Also geht das so erstmal nicht, oder siehst du noch eine Möglichkeit?
                            Einfach wäre vielleicht noch, ein kleines "Toggle-Plugin" zu schreiben.

                            Variante 3)
                            Jetzt könnte ich die 1/1/2 dem Taster zuweisen und vom Decoder einfach und zweifach auswerten lassen. Der sendet dann eben bei zweifach auf die 1/1/2 "auto", oder bei einfach auf die 1/1/4, was das Toggle-Plugin startet. Dieses wiederum toggelt die 1/1/1.

                            Klingt doch eigentlich gut, oder? Einzig nötig wäre dafür, dass der Decoder nicht "auf sich selbst" reagiert. Oben steht, dass es möglich sei, nur auf bestimmte PAs zu reagieren. Die Möglichkeit habe ich aber nicht im Plugin gefunden...

                            Das Toggle-Plugin ist übrigens -selbst für mich- trivial:
                            Code:
                            #!/usr/bin/perl
                            use strict;
                            use strict;
                            
                            plugin_log($plugname,'Startet. Parameter '. $msg{'dst'});
                            $plugin_info{$plugname.'_cycle'} = 86400;
                            $plugin_subscribe{"3/7/6"}{$plugname} = 1; #An Gruppenadresse anmelden 
                            
                                 if (($msg{'dst'} eq ("3/7/6")) && ($msg{'apci'} eq 'A_GroupValue_Write'))
                                 {
                            plugin_log($plugname,'Wurde durch GA aufgerufen');
                                  knx_write("3/7/3",!knx_read("3/7/3",0,1),1);
                                      }
                            Gruß,
                            Hendrik

                            Kommentar

                            Lädt...
                            X