Zurück   KNX-User-Forum > Öffentlicher Bereich > KNX EIB Forum > Code-Schnipsel
knx-user-forum - International KNX Award Winner 2010


Links
Kalender
Spende

Antwort
 
Themen-Optionen Ansicht
  #1  
Alt 05.05.2012, 22:03
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard Neues Plugin: Logikprozessor.pl

Hallo zusammen,
der "Translator", den ich neulich gepostet habe, ist mittlerweile so verbessert, dass er eigentlich eine einfache Logikmaschine geworden ist. Viele einfache Dinge lassen sich damit per Wiregate-Plugin lösen.

Man spezifiziert eine beliebige Zahl von Logiken im Konfigurationsfile, und der Logikprozessor (=Wiregate-Plugin) abonniert die passenden GAs und führt bei eingehenden Telegrammen die entsprechenden Logiken aus. Auch mehrere Logiken für die gleiche GA sind kein Problem.

Hier ein Eindruck der Möglichkeiten:

1. Alle Werte, die auf einer GA gesendet werden, mit 2 multiplizieren und auf einer anderen GA weitergeben. Das kostet nur eine Zeile im Konfigurationsfile:
Code:
    mal2 => { receive=>'9/5/201', transmit=>'9/5/202', translate => sub { 2*$input; }, },
2. Aus einem relativen Dimmwert einen absoluten Dimmwert machen. Die Werte auf der ersten GA werden aufsummiert, das Ergebnis auf der anderen GA gesendet. Wieder nur eine Zeile im Konfigurationsfile:
Code:
    sum => { receive=>'9/5/207', transmit=>'9/5/208', translate => sub { $state-2*$input; }, },
$state enthaelt dabei das jeweils letzte Ergebnis, und das Minuszeichen... ist ein KNX-Geheimnis :-) .

3. Wie oben, aber das Ergebnis auf den Bereich 0-100 limitieren
Code:
    lsum => { receive=>'1/2/7', transmit=>'1/2/8', translate => sub { limit(0,$state-2*$input,100); }, },
4. Hier eine "Treppenlichtfunktion". Auf jeden Schreibzugriff auf die receive-Adresse wird 10min spaeter eine 0 an die transmit-Adresse (hier sind beide gleich) geschickt.
Code:
    stair => { receive=>'1/2/9', transmit=>'1/2/9', delay=>600, translate => 0, },
Verzoegert wird uebrigens nur das Senden, nicht das Ausfuehren der translate-Routine. Neu ist hier der "delay"-Parameter, ausserdem der Spezialfall, dass translate einfach eine Konstante als Rueckgabewert spezifiziert.

Bemerkungen:

* translate darf nur entweder eine Konstante oder ausführbarer Code (sub {...}) sein.

* Damit im Fall transmit==receive der Translator nicht auf sein eigenes Schreibtelegramm immer wieder antwortet, wird nur dann gesendet,
wenn Ergebnis!=Input oder Sender des empfangenen Telegramms!=0 (Wiregate).

Hier noch ein Feature, für das mir momentan kein Beispiel einfällt: analog der Klausel "delay=>600" oben gibt es auch die Spezifikation "transmit_only_on_request=>1". Diese bewirkt, dass das Ergebnis von translate GAR NICHT gesendet wird, sondern dass auf eine spätere Leseanforderung auf der transmit-Adresse mit dem berechneten Ergebnis geantwortet wird.

5. Eine Logik, die einem Lichtanschalten gleich einen Dimmwert hinterherfeuert, und zwar tags und nachts einen verschiedenen:
Code:
    dim => { receive=>'2/2/9', transmit=>'2/3/9', translate => sub { return unless $input; $day ? 80 : 5; }, },
Die Variablen $day_of_week (Mo...So), $weekend (0 oder 1), $time_of_day ("08:34:02"), $hour_of_day ("08"), $day (1 falls zwischen 7 und 23 Uhr, 0 sonst) und $night (entsprechend umgekehrt) sind für diese Logiken vorbesetzt

6. Memory-Funktion. Für KNX-Geräte, die kein Auslesen ihres Statuswerts zulassen (z.B. MDT DaliControl bei Einzel-EVG-Ansteuerung). Sehr einfach:
Code:
    memory => { transmit=>'1/2/9' },
Hier wird folgende Eigenschaft der Logik ausgenutzt: Wenn ein Write-Telegramm auf die Transmit-Adresse kommt, speichert der Logikprozessor den Wert immer automatisch ab. Eine Leseanfrage auf der transmit-GA hingegen wird immer mit dem letzten Wert (hier also dem gespeicherten) beantwortet. Eine receive-Adresse oder translate-Logik werden hier gar nicht gebraucht.

7. Eine einfache UND-Logik mit zwei Eingaengen. Falls ein Telegramm auf einer der beiden receive-GAs empfangen wird, wird die andere Adresse noch ausgelesen, die Logik ausgeführt und das Ergebnis auf der transmit-GA uebermittelt:
Code:
    und => { receive=>['1/2/12','1/2/13'], transmit=>'1/2/14', translate => sub { $input->[0] && $input->[1]; }, },
Neu ist hier die Verwendung eines Arrays für receive. Wenn das geschieht, ist auch $input ein Array, und die Werte sind so angeordnet wie die Gruppenadressen in receive. Arrays für transmit werden übrigens NICHT unterstützt.

8. Ein komplexerer Fall als Demonstration: hier sind receive und transmit wieder einfache GAs, dafür besteht der Status des Logikprozessors aus mehreren Werten. Es wird immer die Summe aus letztem, vorletztem und aktuellem Wert gesendet, und zwar mit 30s Verzoegerung.
Code:
    complex => { receive=>'9/5/205',
                 transmit=>'9/5/206',
                 delay=>30,
                 state => {val1=>0, val2=>0},
                 translate => sub { $state->{val2}=$state->{val1}; $state->{val1}=$state->{result};
                                    $state->{val2}+$state->{val1}+$input; },
    },
Wenn state ein Hash ist, wird der letzte gesendete Wert - also das was sonst im skalaren $state stehen würde - in $state->{result} übergeben.
(Für $state sind nur Hashes und Skalare erlaubt, keine Arrays).

9. Schlussendlich wieder mal Werbung fuer meine GA-Kurznamen. Setzt man im Skript Logikprozessor.pl "$use_short_names=1" (ganz oben im Skript) und verwendet GA-Namen mit eindeutigem Kuerzel (Kuerzel=erstes Wort des Namens), so funktioniert auch das folgende:
Code:
    D_SZ_Decke => { receive=>'LR_SZ_Decke_1', transmit=>'LK_SZ_Decke_1',
                    translate => sub { limit(0,$state-2*$input,100); }, },
Das ist doch leserlicher als Beispiel 3, oder? Hier wird ein relativer Dimmwert (LR) im Schlafzimmer (SZ) durch Skalierung und Summierung in einen absoluten Wert für die Konstantlichtregelung (LK) umgewandelt.

Zum Schluss: Have fun!

Der Logikprozessor ist gerade "frisch aus dem Ofen", macht bei mir im Testbrett (mittlerweile ist das ein Schaltschrank) so einiges, aber "nothing is perfect". Ich freue mich über Verbesserungsvorschläge und Bug reports.

NACHTRÄGLICHES EDIT: Der Logikprozessor ist inzwischen erheblich erweitert, u.a. um eine Verzögerungsfunktion für die Logik (delay), eine Karenzzeit, um zu häufiges Senden oder Zirkellogiken auszuschließen (cool), und eine komplette Timerfunktion mit umfangreichen Möglichkeiten (z.B. Weckfunktion nur an Arbeitstagen um 7:30). Für mehr Infos bitte diesem Thread folgen und unbedingt den Code aus dem SVN verwenden, nicht den hier geposteten (veraltet). Wiregate PL32 ist mittlerweile ebenfalls "Pflicht", zumindest wenn man alle Features nutzen will.


VG,
Fry

Geändert von Fry (17.05.2012 um 23:17 Uhr)
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #2  
Alt 05.05.2012, 22:04
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Hier der Code des Logikprozessors:

Code:
#!/usr/bin/perl -w
##################
# Logikprozessor #
##################
# Wiregate-Plugin
# (c) 2012 Fry under the GNU Public License

#$plugin_info{$plugname.'_cycle'}=0; return 'deaktiviert';

my $use_short_names=0; # 1 fuer GA-Kuerzel (erstes Wort des GA-Namens), 0 fuer die "nackte" Gruppenadresse

# eibgaconf fixen falls nicht komplett indiziert
if($use_short_names && !exists $eibgaconf{ZV_Uhrzeit})
{
    for my $ga (grep /^[0-9\/]+$/, keys %eibgaconf)
    {
        $eibgaconf{$ga}{ga}=$ga;
        my $name=$eibgaconf{$ga}{name};
        next unless defined $name;
        $eibgaconf{$name}=$eibgaconf{$ga};

        next unless $name=~/^\s*(\S+)/;
        my $short=$1;
        $short='ZV_'.$1 if $eibgaconf{$ga}{name}=~/^Zeitversand.*(Uhrzeit|Datum)/;

        $eibgaconf{$ga}{short}=$short;
        $eibgaconf{$short}=$eibgaconf{$ga};
    }
}

# Tools und vorbesetzte Variablen fue die Logiken
sub limit { my ($lo,$x,$hi)=@_; return $x<$lo?$lo:($x>$hi?$hi:$x); }
my $day_of_week=`/bin/date +"%a"`;
my $weekend=($day_of_week=~/Sa|So/);
my $time_of_day=`/bin/date +"%X"`;
my $hour_of_day=substr($time_of_day,0,2);
my $day=($hour_of_day>7 && $hour_of_day<23);
my $night=!$day;

# Konfigurationsfile einlesen
my %logic=();
my $conf="/etc/wiregate/plugin/generic/conf.d/$plugname"; $conf=~s/\.pl$/.conf/;
open FILE, "<$conf" || return "no config found";
$/=undef;
my $lines = <FILE>;
$lines =~ s/(translate\s*=>\s*sub\s*\{)/$1 my \(\$state,\$input\)=\@\_;/sg; 
close FILE;
eval($lines);
return "config error: $@" if $@;

# Aufrufgrund ermitteln
my $event=undef;
if (!$plugin_initflag) 
{ $event='restart'; } # Restart des daemons / Reboot
elsif ($plugin_info{$plugname.'_lastsaved'} > $plugin_info{$plugname.'_last'})
{ $event='modified'; } # Plugin modifiziert
elsif (%msg) { $event='bus'; } # Bustraffic
elsif ($fh) { $event='socket'; } # Netzwerktraffic
else { $event='cycle'; } # Zyklus

# Konfigfile seit dem letzten Mal geaendert?
my $config_modified = (24*60*60*(-M $conf)-time()) > $plugin_info{$plugname.'_configtime'};

# Plugin-Code
my $retval='';

if($event=~/restart|modified/ || $config_modified) 
{
    $plugin_info{$plugname.'_configtime'}=(24*60*60*(-M $conf)-time());

    # alle Variablen loeschen und neu initialisieren, alle GAs abonnieren
    for my $k (grep /^$plugname\_/, keys %plugin_info)
    {
        delete $plugin_info{$k};
    }

    my $count=0;
    my $err=0;

    for my $t (keys %logic)
    {
        # Eintrag pruefen
        if(defined $logic{$t}{receive} && ref $logic{$t}{receive} && ref $logic{$t}{receive} ne 'ARRAY')
        {
            plugin_log($plugname, "Config err: \$logic{$t}{receive} ist weder Skalar noch ARRAY-Referenz ([...]).");
            next;
        }

        if(defined $logic{$t}{translate} && ref $logic{$t}{translate} && ref $logic{$t}{translate} ne 'CODE')
        {
            plugin_log($plugname, "Config err: \$logic{$t}{translate} ist weder Skalar noch CODE-Referenz (sub {...}).");
            next;
        }

        if(defined $logic{$t}{state} && ref $logic{$t}{state} && ref $logic{$t}{state} ne 'HASH')
        {
            plugin_log($plugname, "Config err: \$logic{$t}{state} ist weder Skalar noch HASH-Referenz ({...}).");
            next;
        }

        # transmit-Adresse abonnieren
        my $transmit=groupaddress($logic{$t}{transmit});
        $plugin_subscribe{$transmit}{$plugname}=1;

        $count++;

        # alle receive-Adressen abonnieren (eine oder mehrere)
        my $receive=groupaddress($logic{$t}{receive});

        next unless $receive;
        
        unless(ref $receive)
        { 
            $plugin_subscribe{$receive}{$plugname}=1; 
        }
        else
        {
            for my $rec (@{$receive})
            {
                $plugin_subscribe{$rec}{$plugname}=1;
            }
        }
    }

    $plugin_info{$plugname.'_cycle'}=0;
    $retval.=$count." initialisiert";
}

if($event=~/bus/)
{
    # Bustraffic bedienen - nur Schreibzugriffe der iButtons interessieren
    return unless $msg{apci}=~/A_GroupValue_(Write|Read)/;  

    my $ga=$msg{dst};
    my $in=$msg{value};
    my $keep_subscription=0; # falls am Ende immer noch Null, die GA stornieren

    # welche translate-Logik ist aufgerufen?
    for my $t (keys %logic)
    {
        my $transmit=groupaddress($logic{$t}{transmit});
        my $transmit_ga = ($ga eq $transmit);

        my $receive=groupaddress($logic{$t}{receive});
        my $receive_ga=0; 

        if(defined $receive)
        {
            unless(ref $logic{$t}{receive})
            {
                $receive_ga=1 if $ga eq $receive;
            }
            else
            {
                $receive_ga=1 if grep /^$ga$/, @{$receive};
            }
        }

        next unless $receive_ga || $transmit_ga; # diese Logik nicht anwendbar

        $keep_subscription=1;

        # Sonderfall: Read- und Write-Telegramme auf der Transmit-Adresse?
        if($transmit_ga)
        {    
            # Ein Read-Request auf einer Transmit-GA wird mit dem letzten Ergebnis beantwortet
            # Read-Requests auf die receive-Adressen werden gar nicht beantwortet
            if($msg{apci} eq "A_GroupValue_Read")
            {  
                my $result=$plugin_info{$plugname.'_'.$t.'_result'};
                if(defined $result)
                {
                    knx_write($ga, $result);                
                }
                next;
            }
            elsif(!$receive_ga) # Receive geht vor!
            {
                if(defined $in) # Write-Telegramm: das waren moeglicherweise wir selbst, also nicht antworten
                {
                    $plugin_info{$plugname.'_'.$t.'_result'}=$in; # einfach Input ablegen
                }
                else
                {
                    delete $plugin_info{$plugname.'_'.$t.'_result'};
                }
                next;
            }
        }

        # Wir wissen ab hier: Es liegt ein Write-Telegramm auf einer der receive-Adressen vor

        # Nebenbei berechnen wir noch zwei Flags, die Zirkelkommunikation verhindern sollen
        # (Logik antwortet auf sich selbst in einer Endlosschleife)

        # kommt transmit-GA unter den receive-GAs vor? 
        # Wenn transmit_ga gesetzt ist, ist das schon mal der Fall
        my $possible_circle=$transmit_ga; 

        # war Wiregate der Sender des Telegramms?
        my $sender_is_wiregate=int($msg{src})==0; 

        # Es folgt die eigentliche Logik-Engine - als erstes definiere das Input-Array fuer die Logik
        my $input=$in; # Skalarer Fall (der haeufigste)

        # Array-Fall: bereite Input-Array fuer Logik vor
        if(ref $receive)
        {
            $input=();
            for my $rec (@{$receive})
            {
                my $rec=groupaddress($rec);
                
                $possible_circle=1 if $transmit eq $rec;
                
                if($ga eq $rec)
                {
                    push @{$input}, $in;
                }
                else
                {
                    push @{$input}, knx_read($rec, 300);
                }
            }
        }

        # ab hier liegt $input komplett vor, und nun muss die Logik ausgewertet 
        # und das Resultat auf der Transmit-GA uebertragen
        my $result=undef;
        
        unless(ref $logic{$t}{translate}) 
        {
            # Trivialer Fall: translate enthaelt einen fixen Rueckgabewert
            $plugin_info{$plugname.'_'.$t.'_result'}=$result=$logic{$t}{translate};
        }
        elsif(!ref $logic{$t}{state})
        {
            # Einfacher aber haeufiger Fall: skalarer $state
            # $state mit Ergebnis des letzten Aufrufs vorbesetzen
            my $state=$plugin_info{$plugname.'_'.$t.'_result'};
            
            # Funktionsaufruf, das Ergebnis vom letzten Mal steht in $state
            $result=$logic{$t}{translate}($state,$input);
            
            # Ergebnis des letzten Aufrufs zurueckschreiben
            if(defined $result)
            {
                $plugin_info{$plugname.'_'.$t.'_result'}=$result;
            }
            else
            {
                delete $plugin_info{$plugname.'_'.$t.'_result'};
            }
        }
        else
        {
            # Komplexer Fall: $state-Hash aus %logic initialisieren
            my $state=$logic{$t}{state};
            my @vars=keys %{$state};
            push @vars, 'result';
            
            # Nun die dynamischen Variablen aus plugin_info hinzufuegen
            for my $v (@vars)
            {
                $state->{$v}=$plugin_info{$plugname.'_'.$t.'_'.$v} if defined $plugin_info{$plugname.'_'.$t.'_'.$v};
            }
            
            # Funktionsaufruf, das Ergebnis vom letzten Mal steht in $state->{result}
            $result=$state->{result}=$logic{$t}{translate}($state,$input);
            
            # Alle dynamischen Variablen wieder nach plugin_info schreiben
            # Damit plugin_info nicht durch Konfigurationsfehler vollgemuellt wird, 
            # erlauben wir nur Eintraege mit defined-Werten
            for my $v (@vars)
            {
                if(defined $state->{$v})
                {
                    $plugin_info{$plugname.'_'.$t.'_'.$v}=$state->{$v};
                }
                else
                {
                    # wenn die Logik den Wert undef in eine state-Variable schreibt, 
                    # wird beim naechsten Aufruf wieder der Startwert aus %logic genommen,
                    delete $plugin_info{$plugname.'_'.$t.'_'.$v};
                }
            }
        }
        
        # In bestimmten Sonderfaellen nichts schicken
        next unless defined $result; # Resultat undef => nichts senden
        next if $logic{$t}{transmit_only_on_request};
        next if $possible_circle && $sender_is_wiregate && $in eq $result;
        
        # Falls delay spezifiziert, wird ein "Wecker" gestellt, um in einem spaeteren Aufruf den Wert zu senden
        if($logic{$t}{delay})
        {
            $plugin_info{$plugname.'__'.$t.'_timer'}=time()+$logic{$t}{delay};
            set_timer();
        }
        else
        {
            knx_write($transmit, $result);
        }
    }

    unless($keep_subscription)
    {
        delete $plugin_subscribe{$ga}{$plugname};
    }
}

# Evtl. faellige Timer finden
for my $timer (grep /$plugname\__.*_timer/, keys %plugin_info) # alle Timer
{
    next if time()<$plugin_info{$timer}; # weiter falls noch nicht faellig
    
    # Timer loeschen
    delete $plugin_info{$timer}; 
    
    # Relevanten Eintrag von %logic ermitteln
    $timer=~/$plugname\__(.*)_timer/;
    my $t=$1; 
    
    # Transmit-GA
    my $transmit=groupaddress($logic{$t}{transmit});
    
    # zu sendendes Resultat
    my $result=$plugin_info{$plugname.'_'.$t.'_result'};
    next unless defined $result;
    
    knx_write($transmit, $result);
}

# Timer fuer nachste Aktion setzen
set_timer();   

return unless $retval;
return $retval;


# Zeit bis zum naechsten Aufruf dieses Plugins berechnen

sub set_timer
{
    # optimalen Wert fuer Aufrufzyklus finden, um beim naechsten Aufruf was zu senden
    my $nexttimer=undef;
    for my $timer (grep /$plugname\__.*_timer/, keys %plugin_info) # alle Timer
    {
        $nexttimer=$plugin_info{$timer} if !defined $nexttimer || $plugin_info{$timer}<$nexttimer;
    }

    unless(defined $nexttimer)
    {
        $plugin_info{$plugname."_cycle"}=0;
    }
    else
    {
        my $cycle=$nexttimer-time();
        $cycle=1 if $cycle<1;
        $plugin_info{$plugname."_cycle"}=$cycle;
    }
}

# Umgang mit GA-Kurznamen und -Adressen

sub groupaddress
{
    my $short=shift;

    return unless defined $short;

    if(ref $short)
    {
        my $ga=[];
        for my $sh (@{$short})
        {
            if($sh!~/^[0-9\/]+$/ && defined $eibgaconf{$sh}{ga})
            {
                push @{$ga}, $eibgaconf{$sh}{ga};
            }
            else
            {
                push @{$ga}, $sh;
            }
        }
        return $ga;
    }
    else
    {
        my $ga=$short;

        if($short!~/^[0-9\/]+$/ && defined $eibgaconf{$short}{ga})
        {
            $ga=$eibgaconf{$short}{ga};
        }

        return $ga;
    }
}

sub shortname
{
    my $gas=shift;

    return unless defined $gas;
    return $gas unless $use_short_names;

    if(ref $gas)
    {
        my $sh=[];
        for my $ga (@{$gas})
        {
            if($ga=~/^[0-9\/]+$/ && defined $eibgaconf{$ga}{short})
            {
                push @{$sh}, $eibgaconf{$ga}{short};
            }
            else
            {
                push @{$sh}, $ga;
            }
        }
        return $sh;
    }
    else
    {
        my $sh=$gas;

        if($gas=~/^[0-9\/]+$/ && defined $eibgaconf{$gas}{short})
        {
            $sh=$eibgaconf{$gas}{short};
        }

        return $sh;
    }
}

Geändert von Fry (06.05.2012 um 21:14 Uhr)
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #3  
Alt 05.05.2012, 22:05
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Hier eine Beispielkonfiguration:

Code:
#!/usr/bin/perl
#
# Logikprozessor.pl - Konfiguration
#

%logic=(
    # 1. Alle Werte, die auf einer GA gesendet werden, werden mit 2 multipliziert auf einer anderen GA weitergegeben
    mal2 => { receive=>'9/5/201', transmit=>'9/5/202', translate => sub { 2*$input; }, },

    # 2. Die Werte auf der ersten GA werden aufsummiert, das Ergebis auf der anderen GA gesendet.
    # Damit kann man bspw aus einem relativen Dimmwert einen absoluten Dimmwert machen. 
    sum => { receive=>'9/5/207', transmit=>'9/5/208', translate => sub { $state+$input; }, },
    # $state enthaelt das jeweils letzte Ergebnis.

    # 3. Wie oben, aber das Ergebnis limitiert auf den Bereich 0-100
    lsum => { receive=>'1/2/7', transmit=>'1/2/8', translate => sub { limit(0,$state+$input,100); }, },
 
    # 4. Hier eine "Treppenlichtfunktion". Auf jeden Schreibzugriff auf die receive-Adresse wird 10min spaeter eine 0 an 
    # die transmit-Adresse (hier gleich) geschickt. Verzoegert wird uebrigens nur das Senden, nicht das Ausfuehren der 
    # translate-Routine. Neu ist hier der "delay"-Parameter, ausserdem der Spezialfall, dass translate einfach eine Konstante als
    # Rueckgabewert spezifiziert.
    stair => { receive=>'1/2/9', transmit=>'1/2/9', delay=>600, translate => 0, },
    # Damit im Fall transmit != receive der Logikprozessor nicht auf sein eigenes Schreibtelegramm immer wieder antwortet, wird nur dann gesendet,
    # wenn Ergebnis != Input oder Sender des empfangenen Telegramms!=0 (Wiregate).

    # 5. Memory-Funktion. Wenn ein Write-Telegramm auf die Transmit-Adresse kommt, speichert der Logikprozessor den Wert ab.
    # Das Flag "transmit_on_request" bewirkt, dass nichts gesendet wird, jedoch wird eine Leseanfrage auf der transmit-GA immer
    # mit dem letzten Wert (hier also dem gespeicherten) beantwortet. Damit laesst sich eine Speicherfunktion realisieren. 
    # Hier speichert Logikprozessor also den Input ab und sendet den errechneten (=gespeicherten) Wert NUR AUF ANFRAGE.
    memory => { transmit=>'1/2/9', transmit_only_on_request=>1 },
    # Eine receive-Adresse oder translate-Logik werden hier gar nicht gebraucht.

    # 6. Eine einfache UND-Logik mit zwei Eingaengen. Falls ein Telegramm auf einer der beiden receive-GAs empfangen wird,
    # wird die andere Adresse noch ausgelesen, die Logik angewendet und das Ergebnis auf der transmit-GA uebermittelt
    und => { receive=>['1/2/12','1/2/13'], transmit=>'1/2/14', translate => sub { $input->[0] && $input->[1]; }, },

    # 7. Ein komplexerer Fall nur zur Demonstration: hier besteht der Status des Logikprozessors aus mehreren Werten. 
    # Es wird immer die Summe aus letztem, vorletztem und aktuellem Wert gesendet, und zwar mit 30s Verzoegerung.
    complex => { receive=>'9/5/205', 
                 transmit=>'9/5/206', 
                 delay=>30, 
                 state => {val1=>0, val2=>0}, 
                 translate => sub { $state->{val2}=$state->{val1}; $state->{val1}=$state->{result}; 
                                    $state->{val2}+$state->{val1}+$input; }, 
    },
    # Wenn state ein Hash ist, wird der letzte gesendete Wert in $state->{result} gespeichert.

    # 8. Schlussendlich wieder mal Werbung fuer die GA-Kurznamen. Setzt man im Skript Logikprozessor.pl $use_short_names=1
    # und verwendet GA-Namen mit eindeutigem Kuerzel (=erstes Wort des Namens), so funktioniert auch das folgende:
    D_SZ_Decke => { receive=>'LR_SZ_Decke_1', transmit=>'LK_SZ_Decke_1', 
                    translate => sub { limit(0,$state+20*$input,100); }, },
    # ist doch leserlicher, oder? Hier wird ein relativer Dimmwert durch Skalierung und Summierung 
    # in einen absoluten Wert umgewandelt   
    );

Geändert von Fry (07.05.2012 um 23:37 Uhr)
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #4  
Alt 05.05.2012, 22:07
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Der Logikprozessor.pl kommt nach /etc/wiregate/plugin/generic, und das Konfigurationsfile Logikprozessor.conf nach /etc/wiregate/plugin/generic/conf.d.

Im SVN sind die Files natürlich auch, und falls ich noch Bugs korrigiere oder das Ding erweitere, wird das dort geschehen, nicht hier im Forum.

VG, Fry
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #5  
Alt 07.05.2012, 22:53
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Eine Erweiterung der Logik-Engine ist gerade ins SVN eingecheckt worden, nämlich die Timer-Funktion.

Als Konfigurationsbeispiel hier eine einfache Zeitschaltuhr, die immer um 8:00 und um 10:00 am jeweils zweiten Dienstag jedes Monats eine 1 auf die GA '10/1/15' sendet. Ist wieder nur ein Einzeiler für den Logikprozessor:

Code:
wecker => { transmit=>'10/1/15', timer=>{ time=>['08:00','10:00'], day_of_month=>[(8..14)], day_of_week=>'Di' }, translate => 1 },
Logiken mit timer-Klausel weichen in mehreren Punkten von den bisherigen Logiken ab:

* sie ignorieren die delay-Klausel und senden sofort (ausser transmit_only_on_request ist spezifiziert, siehe erstes Posting oben - dann wird der Wert zwar berechnet, aber erst auf explizite Nachfrage (per Lesetelegramm auf der transmit-Adresse) gesendet)

* jeglicher Bustraffic auf receive-Adressen wird ignoriert. (Falls receive-Adressen spezifiziert sind, werden diese aber beim Timer-Aufruf abgefragt,
um das input-Array vorzubesetzen).

Als timer-Eintrag geht entweder ein einzelnes Hash timer=>{...} wie im Beispiel oben oder eine Liste solcher Eintraege: time=>[{...},{...},{...},...].

Jeder Eintrag MUSS eine Spezifikation time=>'XX:XX' enthalten (auch das darf wieder eine Liste sein, siehe Beispiel) und DARF zusaetzliche, die Geltungstage einschraenkende Klauseln wie year, month, day_of_month,
day_of_week, calendar_week enthalten.

Das Ganze ist mit heißer Nadel gestrickt, hat aber erste Testungen bei mir überstanden.

Über Erfahrungsberichte - auch Bug reports - von Leuten, die dieses Plugin ausprobieren, würde ich mich freuen.

Have fun!
Fry
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #6  
Alt 08.05.2012, 09:52
Benutzer
 
Registriert seit: 05.09.2010
Ort: Sünna
Beiträge: 285
Plusch befindet sich auf einem aufstrebenden Ast
Standard

Hallo,

erstmal bekommst Du meinen vollen Respekt für deine Plugins. Diese machen das Wiregate für mich noch viel nützlicher und auch einfacher konfigurierbar.
Habe vom Logikprozessor mal die Treppenlichtfunktion testen wollen, allerdings ohne Erfolg. Habe das Plugin sowie die Conf.d über den Webmin eingefügt und meine GA eingefügt. Ich wollte das nach dem Einschalten einer Beleuchtung und dem Ablauf der eingestellet Zeit die Beleuchtung wieder abschaltet. Allerdings funktioniert das nicht. Hat das sonst schon mal jemand getestet?

Plusch
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #7  
Alt 08.05.2012, 10:00
Benutzerbild von 2ndsky
Erfahrener Benutzer
 
Registriert seit: 24.10.2010
Ort: Amtzell
Beiträge: 3.689
2ndsky sorgt für eine eindrucksvolle Atmosphäre2ndsky sorgt für eine eindrucksvolle Atmosphäre2ndsky sorgt für eine eindrucksvolle Atmosphäre
Standard

Auch von mir vollsten Respekt! Freu mich schon aufs Ausprobieren!
__________________
Mit freundlichen Grüßen
Niko Will

neustes Projekt: smarthome.py (Logik Engine von mknx)
Dreambox DM8000 - iPhone 5 - iPad 3 - WireGate - ekey - IrTrans - Russound C5 (RIO over TCP Plugin)
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #8  
Alt 08.05.2012, 20:06
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Zitat von Plusch Beitrag anzeigen
Habe vom Logikprozessor mal die Treppenlichtfunktion testen wollen, allerdings ohne Erfolg. Habe das Plugin sowie die Conf.d über den Webmin eingefügt und meine GA eingefügt. Ich wollte das nach dem Einschalten einer Beleuchtung und dem Ablauf der eingestellet Zeit die Beleuchtung wieder abschaltet. Allerdings funktioniert das nicht. Hat das sonst schon mal jemand getestet?
Hallo Plusch,

danke fürs Feedback. Ja, "jemand" hat das getestet (ich :-). Gerade eben auf den Taster gedrückt - jawoll, Licht geht auch wieder aus.

Bitte poste doch etwas mehr Information: dein Konfigfile, hast du das Plugin vom SVN (gut) oder per copy-paste aus dem Forum (schlecht) geholt, was steht im wiregate-Plugin-Log, was im eibd-Log?

Beste Grüße,
Fry
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #9  
Alt 08.05.2012, 21:24
Fry Fry ist offline
Erfahrener Benutzer
 
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
Fry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle AtmosphäreFry sorgt für eine eindrucksvolle Atmosphäre
Standard

Zitat von 2ndsky Beitrag anzeigen
Auch von mir vollsten Respekt! Freu mich schon aufs Ausprobieren!
Danke! Freue mich über Feedback. Mit Sicherheit wird auch nicht alles auf Anhieb klappen, denn mein System hier ist mittlerweile doch etwas non-Standard (modifizierter Wiregate-Daemon). Aber das kriegen wir schon hin...

VG, Fry
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
  #10  
Alt 08.05.2012, 22:01
Benutzer
 
Registriert seit: 05.09.2010
Ort: Sünna
Beiträge: 285
Plusch befindet sich auf einem aufstrebenden Ast
Standard

Hallo,

habe das Plugin sowie die Konfiguration habe ich aus dem SVN.

Das Plugin habe ich direkt aus dem SVN ohne Änderung kopiert.
Meine Konfiguration sieht so aus (habe nur die GA unter Beispiel 4 angepasst):
Code:
#!/usr/bin/perl
#
# Logikprozessor.pl - Konfiguration
#

%logic=(
    # 1. Alle Werte, die auf einer GA gesendet werden, werden mit 2 multipliziert auf einer anderen GA weitergegeben
    mal2 => { receive=>'9/5/201', transmit=>'9/5/202', translate => sub { 2*$input; }, },
    # das "undef" steht da einfach, weil uns der letzte Ergebniswert nicht interessiert

    # 2. Die Werte auf der ersten GA werden aufsummiert, das Ergebis auf der anderen GA gesendet.
    # Damit kann man bspw aus einem relativen Dimmwert einen absoluten Dimmwert machen. 
    sum => { receive=>'9/5/207', transmit=>'9/5/208', translate => sub { $state+$input; }, },
    # $state enthaelt das jeweils letzte Ergebnis.

    # 3. Wie oben, aber das Ergebnis limitiert auf den Bereich 0-100
    lsum => { receive=>'1/2/7', transmit=>'1/2/8', translate => sub { limit(0,$state+$input,100); }, },
 
    # 4. Hier eine "Treppenlichtfunktion". Auf jeden Schreibzugriff auf die receive-Adresse wird 10min spaeter eine 0 an 
    # die transmit-Adresse (hier gleich) geschickt. Verzoegert wird uebrigens nur das Senden, nicht das Ausfuehren der 
    # translate-Routine. Neu ist hier der "delay"-Parameter, ausserdem der Spezialfall, dass translate einfach eine Konstante als
    # Rueckgabewert spezifiziert.
    stair => { receive=>'2/2/0', transmit=>'2/2/0', delay=>5, translate => 0, },
    # Verzoegert wird uebrigens nur das Senden, nicht das Ausfuehren der translate-Routine. 
    # Neu ist hier der "delay"-Parameter, ausserdem der Spezialfall, dass translate einfach eine Konstante 
    # als Rueckgabewert spezifiziert.

    # Weitere Bemerkungen:
    # * translate darf nur entweder eine Konstante oder ausf�hrbarer Code (sub {...}) sein.
    # * Damit im Fall transmit==receive der Translator nicht auf sein eigenes Schreibtelegramm immer wieder antwortet, 
    # wird nur dann gesendet, wenn Ergebnis!=Input oder Sender des empfangenen Telegramms!=0 (Wiregate).
    
    # Damit im Fall transmit != receive der Logikprozessor nicht auf sein eigenes Schreibtelegramm immer wieder antwortet, 
    # wird nur dann gesendet, wenn Ergebnis != Input oder Sender des empfangenen Telegramms!=0 (Wiregate).

    # 5. Hier eine Logik, die den Input bei Eintreffen mit 2 multipliziert, das Resultat aber nur speichert und erst 
    # spaeter auf ein explizites Lesetelegramm hin auf der transmit-Adresse sendet. 
    req => { receive=>'1/2/9', transmit=>'1/2/9', transmit_on_request=>1, translate => sub { 2*$input; }, },

    # 6. Eine Logik, die einem Lichtanschalten gleich einen Dimmwert hinterherfeuert, und zwar tags und nachts einen verschiedenen:
    dim => { receive=>'2/2/9', transmit=>'2/3/9', translate => sub { return unless $input; $day ? 80 : 5; }, },
    # Die Variablen $day_of_week (Mo...So), $day_of_month (01-31), $month (01-12), $year (2012),
    # $weekend (0 oder 1), $weekday (= nicht $weekend), $time_of_day ("08:34:02"), 
    # $hour ("08"), $day (1 falls zwischen 7 und 23 Uhr, 0 sonst) und $night (entsprechend umgekehrt) 
    # sind f�r diese Logiken vorbesetzt (bitte nicht darauf schreiben, koennte unverhergesehene Auswirkungen 
    # auf andere Logiken haben).

    # 7. Memory-Funktion. Fuer KNX-Ger�te, die kein Auslesen ihres Statuswerts zulassen (z.B. MDT DaliControl 
    # bei Einzel-EVG-Ansteuerung). Sehr einfach:
    memory => { transmit=>'1/2/9' },
    # Hier wird folgende Eigenschaft der Logik ausgenutzt: Wenn ein Write-Telegramm auf die Transmit-Adresse kommt, 
    # speichert der Logikprozessor den Wert immer automatisch ab. Eine Leseanfrage auf der transmit-GA hingegen wird 
    # immer mit dem letzten Wert (hier also dem gespeicherten) beantwortet. Eine receive-Adresse oder translate-Logik 
    # werden hier gar nicht gebraucht.

    # 8. Eine einfache UND-Logik mit zwei Eingaengen. Falls ein Telegramm auf einer der beiden receive-GAs empfangen wird,
    # wird die andere Adresse noch ausgelesen, die Logik angewendet und das Ergebnis auf der transmit-GA uebermittelt
    und => { receive=>['1/2/12','1/2/13'], transmit=>'1/2/14', translate => sub { $input->[0] && $input->[1]; }, },

    # 9. Ein komplexerer Fall nur zur Demonstration: hier besteht der Status des Logikprozessors aus mehreren Werten. 
    # Es wird immer die Summe aus letztem, vorletztem und aktuellem Wert gesendet, und zwar mit 30s Verzoegerung.
    complex => { receive=>'9/5/205', 
                 transmit=>'9/5/206', 
                 delay=>30, 
                 state => {val1=>0, val2=>0}, 
         translate => sub { $state->{val2}=$state->{val1}; $state->{val1}=$state->{result}; 
                    $state->{val2}+$state->{val1}+$input; }, 
    },
    # Wenn state ein Hash ist, wird der letzte gesendete Wert in $state->{result} gespeichert.

    # 10. Eine Timer-Funktion. Hier eine einfache Zeitschaltuhr, die immer um 8 Uhr und um 10:00 am jeweils zweiten 
    # Dienstag jedes Monats eine 1 auf Transmit sendet
    wecker => { transmit=>'10/1/15', timer=>{ time=>['08:00','10:00'], day_of_month=>[(8..14)], day_of_week=>'Di' }, translate => 1 }, 
    # Logiken mit timer-Klausel weichen in mehreren Punkten von den bisherigen Logiken ab:
    # * sie ignorieren die delay-Klausel und senden sofort, aber transmit_only_on_request funktioniert
    # * jeglicher Bustraffic auf receive-Adressen wird ignoriert. (Diese werden aber beim Timer-Aufruf abgefragt, 
    # um das input-Array vorzubesetzen).
    # Als timer-Eintrag geht entweder ein einzelnes Hash timer=>{...} wie oben oder eine Liste solcher Eintraege
    # time=>[{...},{...},{...},...]. Jeder Eintrag MUSS eine Spezifikation time=>'XX:XX' enthalten (auch das darf wieder 
    # eine Liste sein) und DARF zusaetzliche, die Geltungstage einschraenkende Klauseln wie year, month, day_of_month,
    # day_of_week, calendar_week enthalten.

    # 11. Schlussendlich wieder mal Werbung fuer die GA-Kurznamen. Setzt man im Skript Logikprozessor.pl $use_short_names=1
    # und verwendet GA-Namen mit eindeutigem Kuerzel (=erstes Wort des Namens), so funktioniert auch das folgende:
    D_SZ_Decke => { receive=>'LR_SZ_Decke_1', transmit=>'LK_SZ_Decke_1', 
            translate => sub { limit(0,$state+20*$input,100); }, },
    # ist doch leserlicher, oder? Hier wird ein relativer Dimmwert durch Skalierung und Summierung 
    # in einen absoluten Wert umgewandelt   
    );
Im wiregate-Plugin-Log steht zu diesem Plugin überhaupt nichts !??

Plusch
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
Antwort

Stichworte
engine, logic, logik, logikprozessor, multifunktionsgateway, plugin, wiregate, wiregate-plugin

Themen-Optionen
Ansicht

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are aus
Pingbacks are aus
Refbacks are aus


Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
[WireGate-Plugin] Neues Plugin: Universeller Szenencontroller Fry Code-Schnipsel 9 15.11.2012 23:07
[WireGate-Plugin] Decoder Plugin zum Haustüröffnen etc. emax WireGate 13 20.10.2012 20:03
Erstmalige Inbetriebnahme Wiregate, erstes Plugin Fechter65 WireGate 10 05.07.2012 08:35
[WireGate-Plugin] Neues Plugin: Universeller Translator Fry Code-Schnipsel 2 05.05.2012 22:10
Plugin startet, obwohl subskribierte GA auskommentiert Patholog WireGate 5 08.11.2011 04:13


Alle Zeitangaben in WEZ +2. Es ist jetzt 08:45 Uhr.



SEO by vBSEO