|
 |
|

05.05.2012, 22:03
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
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)
|

05.05.2012, 22:04
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
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)
|

05.05.2012, 22:05
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
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)
|

05.05.2012, 22:07
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
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
|

07.05.2012, 22:53
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
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
|

08.05.2012, 09:52
|
|
Benutzer
|
|
Registriert seit: 05.09.2010
Beiträge: 285
|
|
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
|

08.05.2012, 10:00
|
 |
Erfahrener Benutzer
|
|
Registriert seit: 24.10.2010
Ort: Amtzell
Beiträge: 3.689
|
|
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)
|

08.05.2012, 20:06
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
Zitat von Plusch
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
|

08.05.2012, 21:24
|
|
Erfahrener Benutzer
|
|
Registriert seit: 14.12.2011
Ort: Hessen
Beiträge: 988
|
|
Zitat von 2ndsky
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
|

08.05.2012, 22:01
|
|
Benutzer
|
|
Registriert seit: 05.09.2010
Beiträge: 285
|
|
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
|
| Themen-Optionen |
|
|
| Ansicht |
Linear-Darstellung
|
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.
HTML-Code ist aus.
|
|
|
Alle Zeitangaben in WEZ +2. Es ist jetzt 08:45 Uhr.
|