|
From: <pf...@us...> - 2012-05-02 22:03:51
|
Revision: 780
http://openautomation.svn.sourceforge.net/openautomation/?rev=780&view=rev
Author: pfry
Date: 2012-05-02 22:03:43 +0000 (Wed, 02 May 2012)
Log Message:
-----------
siehe KNX-Forum
Modified Paths:
--------------
wiregate/plugin/generic/MissGoogle.pl
Added Paths:
-----------
wiregate/plugin/generic/Szenencontroller.pl
wiregate/plugin/generic/Translator.pl
wiregate/plugin/generic/conf.d/Szenencontroller.conf
wiregate/plugin/generic/conf.d/Translator.conf
Modified: wiregate/plugin/generic/MissGoogle.pl
===================================================================
--- wiregate/plugin/generic/MissGoogle.pl 2012-05-02 06:57:30 UTC (rev 779)
+++ wiregate/plugin/generic/MissGoogle.pl 2012-05-02 22:03:43 UTC (rev 780)
@@ -8,7 +8,7 @@
my %text=(
"./Achtung, es wurde ein Einbruch detektiert. Die Polizei wird automatisch benachrichtigt.wav"=>"Achtung, es wurde ein Einbruch detektiert. Die Polizei wird automatisch benachrichtigt",
"./AufWiedersehen.wav"=>"Auf Wiedersehen",
- "./Tschuess.wav"=>"tschüss",
+ "./Tschuess.wav"=>"tschuess",
"./Ciao.wav"=>"tschau",
"./Bitte Schluesselbund ans Schluesselbrett haengen.wav"=>"Bitte Schluesselbund ans Schluesselbrett haengen",
"./Der Trockner ist fertig.wav"=>"Der Trockner ist fertig",
Added: wiregate/plugin/generic/Szenencontroller.pl
===================================================================
--- wiregate/plugin/generic/Szenencontroller.pl (rev 0)
+++ wiregate/plugin/generic/Szenencontroller.pl 2012-05-02 22:03:43 UTC (rev 780)
@@ -0,0 +1,220 @@
+####################
+# Szenencontroller #
+####################
+# 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};
+ }
+}
+
+# Aufrufgrund ermitteln
+my $event=undef;
+if (!$plugin_initflag)
+{ $event='restart'; } # Restart des daemons / Reboot
+#elsif ((stat('/etc/wiregate/plugin/generic/' . $plugname))[9] > time()-2)
+# ab PL30:
+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
+
+# Konfigurationsfile einlesen
+my $conf=$plugname; $conf=~s/\.pl$/.conf/;
+$conf="/etc/wiregate/plugin/generic/conf.d/$conf";
+my %scene=();
+my $err=read_from_config();
+return "config err" if $err;
+
+# Dynamisch definierte Szenen aus plugin_info einlesen
+recall_from_plugin_info();
+
+if($event=~/restart|modified/)
+{
+ # Cleanup aller Szenenvariablen in %plugin_info
+ for my $k (grep /^$plugname\_/, keys %plugin_info)
+ {
+ delete $plugin_info{$k};
+ }
+
+ # Alle Szenen-GAs abonnieren
+ my $count=0;
+ my $scene_lookup='';
+
+ for my $room (keys %scene)
+ {
+ next if $room eq 'storage';
+
+ my $store=$scene{$room}{store};
+ my $recall=$scene{$room}{recall};
+
+ $store=$scene{$room}{store}=$eibgaconf{$store}{ga} if $store!~/^[0-9\/]+$/ && defined $eibgaconf{$store};
+ $recall=$scene{$room}{recall}=$eibgaconf{$recall}{ga} if $recall!~/^[0-9\/]+$/ && defined $eibgaconf{$recall};
+
+ next unless defined $store && defined $recall;
+
+ $scene_lookup.="St($store)=>'$room', Rc($recall)=>'$room', ";
+
+ $plugin_subscribe{$store}{$plugname}=1;
+ $plugin_subscribe{$recall}{$plugname}=1;
+
+ $count++;
+ }
+
+ $plugin_info{$plugname.'__SceneLookup'}=$scene_lookup;
+ $plugin_info{$plugname.'_cycle'}=0;
+
+ return $count." initialisiert";
+}
+
+if($event=~/bus/)
+{
+ # nur auf Write-Telegramme reagieren
+ return if $msg{apci} ne 'A_GroupValue_Write';
+
+ # Aufruf durch GA
+ my $ga=$msg{dst};
+ my $n=int($msg{value}); # die Szenennummer
+
+ # die betreffende Szene finden
+ unless($plugin_info{$plugname.'__SceneLookup'}=~/(St|Rc)\($ga\)=>\'(.+?)\',/)
+ {
+ delete $plugin_subscribe{$ga}{$plugname}; # unbekannte GA
+ return;
+ }
+
+ my $cmd=$1; chop $cmd;
+ my $room=$2;
+
+ if($eibgaconf{$ga}{DPTSubId} eq '1.017')
+ {
+ # Szenennummer aus physikalischer Adresse ableiten falls DPTSubId==1.017
+ return unless $msg{src}=~/[0-9]+\.[0-9]+\.([0-9]+)/;
+ $n=$1;
+ }
+ elsif($scene{$room}{store} eq $scene{$room}{recall})
+ {
+ # Speichern oder Abrufen? Falls beides die gleiche GA, aus 7. Bit der Szenennummer ableiten
+ $cmd = ($n & 0x80)?'S':'R';
+ $n = ($n & 0x7f)+1;
+ }
+ else # Aufruf mit Wert = Szenennummer
+ {
+ $n = 128 if $n>128; # begrenzen auf max. 128
+ }
+
+ # Szenencode
+ my $z="$room\__$n";
+
+ # Debugging
+# plugin_log($plugname, "Szene $z ".($cmd eq 'S'?'speichern':'abrufen'));
+
+ if($cmd eq 'S') # Szene speichern
+ {
+ delete $scene{$z};
+
+ for my $ga (keys %{$scene{$room}{gas}})
+ {
+ my $wga=$scene{$room}{gas}{$ga}; # auf diese GA muss spaeter geschrieben werden
+ $wga=$eibgaconf{$wga}{short} if $wga=~/^[0-9\/]+$/ && $use_short_names && defined $eibgaconf{$wga}{short};
+ $ga=$eibgaconf{$ga}{ga} if $ga!~/^[0-9\/]+$/ && defined $eibgaconf{$ga};
+ $scene{$z}{$wga}=knx_read($ga,300);
+ delete $scene{$z}{$wga} unless defined $scene{$z}{$wga};
+ }
+
+ if($scene{storage} eq 'configfile')
+ {
+ store_to_config($z);
+ }
+ else
+ {
+ store_to_plugin_info($z);
+ }
+ }
+ else # Szene abrufen
+ {
+ for my $v (keys %{$scene{$z}})
+ {
+ my $ga=$v;
+ $ga=$eibgaconf{$ga}{ga} if $ga!~/^[0-9\/]+$/ && defined $eibgaconf{$ga};
+ knx_write($ga,$scene{$z}{$v});
+ }
+ }
+}
+
+return;
+
+########## Datenpersistenz - Speichern und Einlesen ###############
+
+sub read_from_config
+{
+ open CONFIG, "<$conf" || return "no config found";
+ my @lines = <CONFIG>;
+ close CONFIG;
+ eval("@lines");
+ return "config error" if $@;
+}
+
+sub store_to_config
+{
+ my $z=shift; # die Szenenbezeichnung
+
+ open CONFIG, ">>$conf";
+ print CONFIG "\$scene{$z}={";
+ for my $v (sort keys %{$scene{$z}})
+ {
+ print CONFIG sprintf "'$v'=>%.2f, ", $scene{$z}{$v};
+ }
+ print CONFIG "};\n";
+ close CONFIG;
+}
+
+# alternativ: speichern ins globale Hash plugin_info
+
+sub store_to_plugin_info
+{
+ my $z=shift; # die Szenenbezeichnung
+
+ # Alle Laufzeitvariablen im Hash %{$dyn}
+ # in das (flache) Hash plugin_info schreiben
+ for my $k (grep /^$plugname\__$z/, keys %plugin_info)
+ {
+ delete $plugin_info{$k};
+ }
+
+ for my $v (keys %{$scene{$z}})
+ {
+ $plugin_info{$plugname.'__'.$z.'__'.$v}=$scene{$z}{$v};
+ }
+}
+
+sub recall_from_plugin_info
+{
+ for my $k (grep /^$plugname\__/, keys %plugin_info)
+ {
+ next unless($k=~/^$plugname\__([A-Z0-9 ]+__[0-9]+)__(.*)$/i);
+ my ($z,$v)=($1,$2);
+ $scene{$z}{$v}=$plugin_info{$k};
+ }
+}
+
Added: wiregate/plugin/generic/Translator.pl
===================================================================
--- wiregate/plugin/generic/Translator.pl (rev 0)
+++ wiregate/plugin/generic/Translator.pl 2012-05-02 22:03:43 UTC (rev 780)
@@ -0,0 +1,189 @@
+##############
+# Translator #
+##############
+# 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};
+ }
+}
+
+sub limit { my ($lo,$x,$hi)=@_; return $x<$lo?$lo:($x>$hi?$hi:$x); }
+
+# Konfigurationsfile einlesen
+my %trans=();
+my $conf=$plugname; $conf=~s/\.pl$/.conf/;
+open FILE, "</etc/wiregate/plugin/generic/conf.d/$conf" || return "no config found";
+my @lines = <FILE>;
+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
+
+# Plugin-Code
+if($event=~/restart|modified/)
+{
+ # 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 $rxtx_lookup='';
+
+ for my $t (keys %trans)
+ {
+ my $receive=$trans{$t}{receive};
+ my $transmit=$trans{$t}{transmit};
+
+ $receive=$eibgaconf{$receive}{ga} if $receive!~/^[0-9\/]+$/ && defined $eibgaconf{$receive};
+ $transmit=$eibgaconf{$transmit}{ga} if $transmit!~/^[0-9\/]+$/ && defined $eibgaconf{$transmit};
+
+ next unless defined $receive && defined $transmit;
+
+ $rxtx_lookup.="Rx($receive)=>'$t', Tx($transmit)=>'$t', ";
+
+ $plugin_subscribe{$receive}{$plugname}=1;
+ $plugin_subscribe{$transmit}{$plugname}=1;
+
+ $count++;
+
+ $plugin_info{$plugname.'_'.$t.'_result'}=undef;
+
+ if(ref $trans{$t}{state})
+ {
+ for my $v (keys %{$trans{$t}{state}})
+ {
+ $plugin_info{$plugname.'_'.$t.'_'.$v}=$trans{$t}{state}{$v};
+ }
+ }
+ elsif(defined $trans{$t}{state})
+ {
+ $plugin_info{$plugname.'_'.$t.'_result'}=$trans{$t}{state};
+ }
+ }
+
+ $plugin_info{$plugname.'__RxTxLookup'}=$rxtx_lookup;
+ $plugin_info{$plugname.'_cycle'}=0;
+
+ return $count." initialisiert";
+}
+
+# Bustraffic bedienen - nur Schreibzugriffe der iButtons interessieren
+if($event=~/bus/)
+{
+ return if $msg{apci} eq "A_GroupValue_Response";
+
+ my $ga=$msg{dst};
+
+ unless($plugin_info{$plugname.'__RxTxLookup'}=~/(Tx|Rx)\($ga\)=>\'(.+?)\',/)
+ {
+ delete $plugin_subscribe{$ga}{$plugname}; # unbekannte GA
+ return;
+ }
+
+ my $cmd=$1; chop $cmd;
+ my $t=$2;
+
+ if($msg{apci} eq "A_GroupValue_Read")
+ {
+ # Ein Read-Request auf einer Transmit-GA wird mit dem letzten Ergebnis beantwortet
+ knx_write($ga, $plugin_info{$plugname.'_'.$t.'_result'}) if $cmd eq 'T';
+ return;
+ }
+ elsif($msg{apci} eq "A_GroupValue_Write")
+ {
+ my $input=$msg{value};
+
+ # Write-Telegramm auf unserer Transmit-Adresse?
+ # Vorsicht! - das koennten wir selbst gewesen sein, also nicht antworten!
+ if($cmd eq 'T')
+ {
+ $plugin_info{$plugname.'_'.$t.'_result'}=$input; # einfach Input ablegen
+ return;
+ }
+
+ my $result=undef;
+
+ # Ein Write-Request auf einer Receive-GA wird uebersetzt und das Resultat auf der Transmit-GA uebertragen
+ if(ref $trans{$t}{state})
+ {
+ # Komplexer state-Hash: Basis sind die Werte im Configfile
+ my $state=$trans{$t}{state};
+
+ # Nun die dynamischen Variablen aus plugin_info hinzufuegen
+ for my $k (keys %plugin_info)
+ {
+ next unless $k=~/^$plugname\_$t\_(.*)$/;
+ my $v=$1;
+ $state->{$v}=$plugin_info{$plugname.'_'.$t.'_'.$v};
+ }
+
+ # Funktionsaufruf, das Ergebnis vom letzten Mal steht in $state->{result}
+ $result=$trans{$t}{translate}($state,$input);
+
+ # Alle dynamischen Variablen wieder nach plugin_info schreiben
+ # Damit plugin_info nicht durch Konfigurationsfehler vollgemuellt wird,
+ # erlauben wir nur vorhandene Eintraege
+ for my $v (keys %{$state})
+ {
+ next unless exists $plugin_info{$plugname.'_'.$t.'_'.$v};
+ $plugin_info{$plugname.'_'.$t.'_'.$v}=$state->{$v};
+ }
+ }
+ else # Einfacher Fall - skalare state-Variable
+ {
+ # Einfache state-Skalar: Ergebnis des letzten Aufrufs
+ my $state=$plugin_info{$plugname.'_'.$t.'_result'};
+
+ # Funktionsaufruf, das Ergebnis vom letzten Mal steht in $state
+ $result=$trans{$t}{translate}($state,$input);
+ }
+
+ # Ergebnis des letzten Aufrufs zurueckschreiben
+ $plugin_info{$plugname.'_'.$t.'_result'}=$result;
+
+ # Uebersetzung auf Bus schreiben, ausser im Sonderfall receive==transmit, dann nur auf Anfrage senden
+ my $receive=$trans{$t}{receive};
+ my $transmit=$trans{$t}{transmit};
+
+ # Debugging
+ plugin_log($plugname, "$input ($receive) -> $result ($transmit)");
+
+ $receive=$eibgaconf{$receive}{ga} if $receive!~/^[0-9\/]+$/ && defined $eibgaconf{$receive};
+ $transmit=$eibgaconf{$transmit}{ga} if $transmit!~/^[0-9\/]+$/ && defined $eibgaconf{$transmit};
+
+ knx_write($transmit, $result) unless($transmit eq $receive);
+ }
+}
+
+return;
Added: wiregate/plugin/generic/conf.d/Szenencontroller.conf
===================================================================
--- wiregate/plugin/generic/conf.d/Szenencontroller.conf (rev 0)
+++ wiregate/plugin/generic/conf.d/Szenencontroller.conf 2012-05-02 22:03:43 UTC (rev 780)
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+#
+# Konfiguration Szenencontroller ######################################
+#
+
+%scene=(
+
+ # Storage auf 'configfile' setzen, wenn die Szenen hier im Konfigfile gespeichert werden sollen.
+ # Sie ueberleben in diesem Fall sogar das Loeschen des plugin_info und gelten somit als "fest verdrahtet".
+ # Ansonsten 'plugin_info' setzen, dann werden die Szenen im %plugin_info gespeichert.
+ # 'configfile' hat allerdings noch die Vorteile, dass die Werte hier editierbar werden und dass plugin_info
+ # nicht so "zugemuellt" wird.
+ storage=>'configfile', # 'plugin_info' oder 'configfile'
+
+ # Das folgende Beispiel konfiguriert Szenen fuer ein Zimmer (Schlafzimmer).
+ #
+ Schlafzimmer => {store=>'0/1/2', recall=>'0/1/3', gas=>{'1/2/3'=>'1/2/3', '1/2/4'=>'1/2/5'}},
+ #
+ # Die GA zum Aufrufen "Recall" einer Szene (zB kurzer Tastendruck am Taster) ist 0/1/3,
+ # die GA zum Speichern "Store" einer Szene (langer Druck) ist 0/1/2.
+ # Beim Speichern werden die Werte aus 1/2/3 und 1/2/4 ausgelesen und in die entsprechende Szenennummer
+ # abgelegt, beim Abrufen dieser Szenennummer werden genau diese Werte wieder in 1/2/3 und 1/2/5 zurueck-
+ # geschrieben.
+ #
+ # (Die Zuordnungen unter gas enthalten immer ein Paar: die erste GA wird beim Speichern (Store) der Szene
+ # ausgelesen und ihr Wert gespeichert, die zweite GA wird beim Aufrufen (Recall) mit dem gespeicherten Wert
+ # beschrieben.)
+ #
+ # Noch einige Details:
+ #
+ # 1. Szenennummer bei "Wert uebermitteln"-Taster (DPTSubId 5.010, in ETS als "Wert" konfiguriert):
+ # Sowohl bei Store als auch bei Recall wird der Inhalt des Bustelegramms als Index der Szene verwendet.
+ # Geschickterweise konfiguriert man das so, dass jeder Taster einen eindeutigen, festen Wert uebermittelt.
+ # So kann jede Taste im Raum jeweils eine Szene speichern und wieder aufrufen, sie muss dafuer einfach eine
+ # Zahl (sinnvollerweise einen 8bit-Wert, DPTSubId 5.010), uebermitteln.
+ #
+ # 2. Szene abrufen/speichern bei "Szenen"-Tastern (in ETS als "Szene" konfiguriert):
+ # Hier wird die Szenennummer wie oben im Taster konfiguriert, dieselbe (!) GA fuer store und recall
+ # gesetzt und wieder die DPTSubId 5.010 in /etc/wiregate/eibga.conf konfiguriert.
+ # In diesem Fall wird die Unterscheidung zwischen Store und Recall durch das 7. Bit des Wertes getroffen,
+ # was kompatibel mit "Szenen"-Tastern ist (zumindest klappt es mit meinen MDTs).
+ #
+ # 3. Szenennummer bei "Schalten"-Taster (DPTSubId 1.017, in ETS als einfaches "Schalten" ohne Wert konfiguriert):
+ # Falls die DPTSubId 1.017 ist (Trigger) - typisch fuer "Schalten"-Taster, kann der Inhalt des Telegramms
+ # keine Szenennummer uebermitteln. Dann wird als Szenennummer einfach die physikalische Adresse des Tasters
+ # genommen. So koennen auch Taster, die ueber eine lang-kurz-Schaltung verfuegen aber keine Werte senden,
+ # jeweils eine eigene Szene ablegen.
+ #
+ # 4. Schlussendlich wieder mal Werbung fuer die GA-Kurznamen. Setzt man im Skript Translator.pl $use_short_names=1
+ # und verwendet GA-Namen mit eindeutigem Kuerzel (=erstes Wort des Namens), so funktioniert auch das folgende:
+ Schlafzimmer2 => {store=>'ZS_SZ', recall=>'ZA_SZ', gas=>{'LI_SZ'=>'LI_SZ', 'JX_SZ'=>'JW_SZ', 'JQ_SZ'=>'JP_SZ'}},
+ # ist doch leserlicher, oder? SZ=Schlafzimmer, ZA=Szene abrufen, ZS=Szene speichern, LI=Licht,
+ # JX=Jalousiewinkel abfragen, JW=Jalousiewinkel einstellen, JQ=Jalousieposition abfragen, JP=Jalousie positionieren
+
+ );
+
+
+# Im folgenden werden Szenen abgelegt, die auch ein Editierien Neuinitialisieren
+# des Szenencontrollers ueberleben.
+
+# Wenn oben als "storage" die Angabe "configfile" gemacht wird, werden
+# neue Szenen hier abgelegt und ueberleben damit auch eine Neuinitialisierung
+
+# Wenn oben "plugin_info" festgelegt wurde, so dienen die hier festgelegten
+# Szenen als Grundstock bei einer Initialisierung, die danach per Tastendruck
+# gespeicherten Szenen werden aber in plugin_info geschrieben und
+# haben dann hoehere Prioritaet, ueberleben aber eben keinen Reset.
Added: wiregate/plugin/generic/conf.d/Translator.conf
===================================================================
--- wiregate/plugin/generic/conf.d/Translator.conf (rev 0)
+++ wiregate/plugin/generic/conf.d/Translator.conf 2012-05-02 22:03:43 UTC (rev 780)
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+#
+# Translator.pl - Konfiguration
+
+%trans=(
+
+ # 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 { my ($state,$input)=@_; 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 { my ($state,$input)=@_; $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 { my ($state,$input)=@_; limit(0,$state+$input,100); }, },
+
+ # 4. Schliesslich eine Memory-Funktion: wenn receive==transmit, so wird nur auf eine Leseanfrage gesendet.
+ # Hier speichert Translator also den Input ab und sendet den errechneten (=gespeicherten) Wert NUR AUF ANFRAGE
+ memory => { receive=>'1/2/9', transmit=>'1/2/10', translate => sub { my ($state,$input)=@_; $input; }, },
+
+ # 5. Ein komplexerer Fall: hier besteht der Status des Translators aus mehreren Werten.
+ # Es wird immer die Summe aus letztem, vorletztem und aktuellem Wert gesendet.
+ complex => { receive=>'9/5/205', transmit=>'9/5/206', state => {val1=>0, val2=>0},
+ translate => sub { my ($state,$input)=@_;
+ $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.
+
+ # 6. Schlussendlich wieder mal Werbung fuer die GA-Kurznamen. Setzt man im Skript Translator.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', transmit=>'LK_SZ_Decke',
+ translate => sub { my ($state,$input)=@_; limit(0,$state+20*$input,100); }, },
+ # ist doch leserlicher, oder? Hier wird ein relativer Dimmwert durch Skalierung und Summierung
+ # in einen absoluten Wert umgewandelt
+
+ );
+
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|