|
From: <pf...@us...> - 2012-05-07 20:47:02
|
Revision: 795
http://openautomation.svn.sourceforge.net/openautomation/?rev=795&view=rev
Author: pfry
Date: 2012-05-07 20:46:56 +0000 (Mon, 07 May 2012)
Log Message:
-----------
Modified Paths:
--------------
wiregate/plugin/generic/Logikprozessor.pl
wiregate/plugin/generic/conf.d/Logikprozessor.conf
Modified: wiregate/plugin/generic/Logikprozessor.pl
===================================================================
--- wiregate/plugin/generic/Logikprozessor.pl 2012-05-07 18:51:21 UTC (rev 794)
+++ wiregate/plugin/generic/Logikprozessor.pl 2012-05-07 20:46:56 UTC (rev 795)
@@ -30,21 +30,32 @@
# 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 $date=`/bin/date +"%W,%a,%u,%m,%d,%Y,%H,%M,%X"`;
+plugin_log($plugname, "Datum/Uhrzeit konnte nicht lesbar.") unless $date=~/^(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/;
+my $calendar_week=$1;
+my $day_of_week=$2;
+my $day_of_week_no=$3;
+my $month=int($4);
+my $day_of_month=int($5);
+my $year=int($6);
+my $hour=int($7);
+my $minute=int($8);
+my $time_of_day=$9; # '08:30:43'
+my $weekend=($day_of_week_no>=6);
+my $weekday=!$weekend;
+my $day=($hour>7 && $hour<23);
my $night=!$day;
+my $systemtime=time();
# Konfigurationsfile einlesen
-my %devices=(0=>'Wiregate');
my %logic=();
my $conf="/etc/wiregate/plugin/generic/conf.d/$plugname"; $conf=~s/\.pl$/.conf/;
open FILE, "<$conf" || return "no config found";
-my @lines = <FILE>;
+$/=undef;
+my $lines = <FILE>;
+$lines =~ s/((?:translate|\'translate\'|\"translate\")\s*=>\s*sub\s*\{)/$1 my \(\$state,\$input\)=\@\_;/sg;
close FILE;
-eval("@lines");
+eval($lines);
return "config error: $@" if $@;
# Aufrufgrund ermitteln
@@ -97,13 +108,26 @@
next;
}
+ if(defined $logic{$t}{timer} && defined $logic{$t}{delay})
+ {
+ plugin_log($plugname, "Config err: \$logic{$t}: delay und timer festgelegt, ignoriere delay");
+ }
+
# transmit-Adresse abonnieren
my $transmit=groupaddress($logic{$t}{transmit});
$plugin_subscribe{$transmit}{$plugname}=1;
$count++;
- # alle receive-Adressen abonnieren (eine oder mehrere)
+ # Timer-Logiken reagieren nicht auf Bustraffic auf den receive-Adressen
+ # fuer Timer-Logiken: ersten Call berechnen
+ if($logic{$t}{timer})
+ {
+ set_next_call($t);
+ next;
+ }
+
+ # fuer Nicht-Timer-Logiken: alle receive-Adressen abonnieren (eine oder mehrere)
my $receive=groupaddress($logic{$t}{receive});
next unless $receive;
@@ -121,7 +145,6 @@
}
}
- $plugin_info{$plugname.'_cycle'}=0;
$retval.=$count." initialisiert";
}
@@ -143,7 +166,7 @@
my $receive=groupaddress($logic{$t}{receive});
my $receive_ga=0;
- if(defined $receive)
+ if(defined $receive && !$logic{$t}{timer})
{
unless(ref $logic{$t}{receive})
{
@@ -173,7 +196,7 @@
}
next;
}
- elsif(!$receive_ga) # Receive geht vor!
+ elsif(!$receive_ga) # Receive geht vor - bei Timer-Logiken ist receive_ga immer 0
{
if(defined $in) # Write-Telegramm: das waren moeglicherweise wir selbst, also nicht antworten
{
@@ -192,109 +215,30 @@
# 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)
+ # Aufruf der Logik-Engine
+ my $result=execute_logic($t, $receive, $ga, $in);
- # Array-Fall: bereite Input-Array fuer Logik vor
- if(ref $receive)
+ # In bestimmten Sonderfaellen nichts schicken
+ next unless defined $result; # Resultat undef => nichts senden
+ next if $logic{$t}{transmit_only_on_request};
+
+ # Zirkelaufruf ausschliessen
+ if($sender_is_wiregate && $in eq $result)
{
- $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);
- }
- }
+ # kommt transmit-GA unter den receive-GAs vor?
+ # Wenn transmit_ga gesetzt ist, ist das schon mal der Fall
+ next if $transmit_ga;
+ next if !ref $receive && ($transmit eq $receive);
+ next if ref $receive && grep /^$transmit$/, @{$receive};
}
- # 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();
+ $plugin_info{$plugname.'__'.$t.'_timer'}=$systemtime+$logic{$t}{delay};
}
else
{
@@ -308,58 +252,301 @@
}
}
-# Evtl. faellige Timer finden
+# Evtl. faellige Timer finden, gleichzeitig Timer fuer nachste Aktion setzen
+my $nexttimer=undef;
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);
+ if(time()>=$plugin_info{$timer}) # Timer faellig? -> dann ausfuehren bzw. Resultat senden
+ {
+ # Relevanten Eintrag von %logic ermitteln
+ $timer=~/$plugname\__(.*)_timer/;
+ my $t=$1;
+
+ # Timer loeschen bzw. neu setzen
+ set_next_call($t);
+
+ # zu sendendes Resultat = zuletzt berechnetes Ergebnis der Logik
+ my $result=$plugin_info{$plugname.'_'.$t.'_result'};
+
+ # ...es sei denn, es ist eine timer-Logik. Die muss jetzt ausgefuehrt werden
+ if($logic{$t}{timer})
+ {
+ # Aufruf der Logik-Engine
+ $result=execute_logic($t, groupaddress($logic{$t}{receive}), undef, undef);
+ }
+
+ # Transmit-GA
+ my $transmit=groupaddress($logic{$t}{transmit});
+
+ next unless defined $result;
+ next if $logic{$t}{transmit_only_on_request};
+
+ knx_write($transmit, $result);
+ }
+ else # noch nicht faelliger Timer
+ {
+ $nexttimer=$plugin_info{$timer} if !defined $nexttimer || $plugin_info{$timer}<$nexttimer;
+ }
}
-# Timer fuer nachste Aktion setzen
-set_timer();
+# Cycle auf naechsten Aufruf setzen
+unless(defined $nexttimer)
+{
+ $plugin_info{$plugname."_cycle"}=0; # kein Aufruf noetig
+}
+else
+{
+ my $cycle=$nexttimer-time();
+ $cycle=1 if $cycle<1;
+ $plugin_info{$plugname."_cycle"}=$cycle;
+}
return unless $retval;
return $retval;
-# Zeit bis zum naechsten Aufruf dieses Plugins berechnen
+# Fuer Logiken mit timer-Klausel: Zeit des naechsten Aufrufs bestimmen
-sub set_timer
+sub next_day
{
- # 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
+ my $d=shift;
+
+ my $leapyear = ($d->{year} % 4)==0 && ($d->{year} % 100!=0 || $d->{year} % 400==0);
+ my @days_in_month=(0,31,28+$leapyear,31,30,31,30,31,31,30,31,30,31);
+
+ $d->{day_of_week} = ($d->{day_of_week} % 7)+1;
+ $d->{calendar_week} += $d->{day_of_week}==1;
+ $d->{day_of_month} = ($d->{day_of_month} % $days_in_month[$d->{month}])+1;
+ $d->{month} += $d->{day_of_month}==1;
+ $d->{month}=1 if $d->{month}==13;
+ $d->{year} += ($d->{day_of_month}==1 && $d->{month}==1);
+
+ return $d;
+}
+
+sub schedule_matches_day
+{
+ my ($schedule,$day)=@_;
+ # Beide Argumente sind Hash-Referenzen, wobei schedule jeweils auf Listen zeigt, aber $day alle Kategorien enthaelt
+ # zB $day={year=>2012,month=>4,day_of_month=>13,calendar_week=>16,day_of_week=>4,...};
+
+ my $match=1;
+
+ for my $c (keys %{$schedule})
{
- $nexttimer=$plugin_info{$timer} if !defined $nexttimer || $plugin_info{$timer}<$nexttimer;
+ next if $c eq 'time'; # es geht nur um Tage
+ unless(grep /^$day->{$c}$/, @{$schedule->{$c}})
+ {
+ $match=0;
+ last;
+ }
}
- unless(defined $nexttimer)
+ return $match;
+}
+
+sub set_next_call
+{
+ my $t=shift; # der relevante Eintrag in %logic
+ my $nextcall=undef;
+ my $days_until_nextcall=0;
+
+ # $logic{$t}{timer} ist eine Liste oder ein einzelner Eintrag
+ # jeder solche Eintrag ist ein Hash im Format
+ # {day_of_month=>[(1..7)],day_of_week=>'Mo',time=>['08:30','09:20']}
+ # das gerade genannte Beispiel bedeutet "jeden Monat jeweils der erster Montag, 8:30 oder 9:20"
+ # verwendbare Klauseln sind year, month, day_of_month, calendar_week, day_of_week und time
+ # Pflichtfeld ist lediglich time, die anderen duerfen auch entfallen.
+ # Jeder Wert darf ein Einzelwert oder eine Liste sein.
+ my $schedule=$logic{$t}{timer};
+ my $today={year=>$year,month=>$month,day_of_month=>$day_of_month,calendar_week=>$calendar_week,day_of_week=>$day_of_week_no};
+ my $time_of_day=`/bin/date +"%X"`;
+
+ # Schedule-Form standardisieren (alle Eintraege in Listenform setzen und Wochentage durch Zahlen ersetzen)
+ # dabei gleich schauen, ob HEUTE noch ein Termin ansteht
+ $schedule=[$schedule] if ref $schedule eq 'HASH';
+ my %weekday=(Mo=>1,Di=>2,Mi=>3,Do=>4,Fr=>5,Sa=>6,So=>7);
+
+ for my $s (@{$schedule})
{
- $plugin_info{$plugname."_cycle"}=0;
+ unless(ref $s eq 'HASH')
+ {
+ plugin_log($plugname, "Logiktimer zu Logik '$t' ist kein Hash oder Liste von Hashes");
+ next;
+ }
+ unless(defined $s->{time})
+ {
+ plugin_log($plugname, "Logiktimer zu Logik '$t' enthaelt mindestens einen Eintrag ohne Zeitangabe (time=>...)");
+ next;
+ }
+
+ for my $k (keys %{$s})
+ {
+ unless($k=~/^(year|month|calendar_week|day_of_month|day_of_week|time)$/)
+ {
+ plugin_log($plugname, "Logiktimer zu Logik '$t': Unerlaubter Eintrag '$k'; erlaubt sind year, month, calendar_week, day_of_month, day_of_week, und Pflichteintrag ist time");
+ next;
+ }
+
+ unless(!ref $s->{$k} || ref $s->{$k} eq 'ARRAY')
+ {
+ plugin_log($plugname, "Logiktimer zu Logik '$t': '$k' muss auf Skalar oder Array ($k=>[...]) verweisen");
+ next;
+ }
+
+ $s->{$k}=[$s->{$k}] unless ref $s->{$k} eq 'ARRAY'; # alle Kategorien in Listenform
+ map $_=$weekday{$_}, @{$s->{$k}} if $k eq 'day_of_week'; # Wochentage in Zahlenform
+ @{$s->{$k}}=sort @{$s->{$k}}; # alle Listen sortieren
+ }
+
+ # Steht heute aus diesem Schedule noch ein Termin an?
+ next unless schedule_matches_day($s,$today) && $s->{time}[-1] gt $time_of_day;
+
+ # Heute steht tatsaechlich noch ein Termin an! Welcher ist der naechste?
+ # Rueckwaerts durch die Liste $s->{time} suchen
+ my $nc=undef;
+ for(my $i=$#{$s->{time}}; $i>=0 && $s->{time}[$i] gt $time_of_day; $i--) { $nc=$s->{time}[$i]; }
+ $nextcall=$nc unless defined $nextcall && $nextcall lt $nc;
}
+
+ # Wenn $nextcall hier bereits definiert, enthaelt es die naechste Aufrufzeit des Timers im Format "08:30"
+ my $schedules_done=0;
+
+ # falls nextcall noch nicht definiert, geht es jetzt um den naechsten Tag mit Termin
+ until($schedules_done || defined $nextcall)
+ {
+ $schedules_done=1;
+ $days_until_nextcall++;
+ $today=next_day($today);
+
+ for my $s (@{$schedule})
+ {
+ $schedules_done=0 if !defined $s->{year} || $s->{year}[-1]>=$today->{year};
+ next unless schedule_matches_day($s,$today);
+
+ # an diesem Tag gibt es einen Termin! Wann ist der erste?
+ $nextcall=$s->{time}[0] unless defined $nextcall && $nextcall lt $s->{time}[0];
+ }
+ }
+
+ if(defined $nextcall)
+ {
+ plugin_log($plugname, "Naechster Aufruf der Logik '$t' um $nextcall".($days_until_nextcall?" in $days_until_nextcall Tagen.":"."));
+
+ # Zeitdelta zu jetzt berechnen
+ my $seconds=3600*(substr($nextcall,0,2)-substr($time_of_day,0,2))
+ +60*(substr($nextcall,3,2)-substr($time_of_day,3,2))-substr($time_of_day,6,2);
+ $nextcall=$systemtime+$seconds+3600*24*$days_until_nextcall;
+ $plugin_info{$plugname.'__'.$t.'_timer'}=$nextcall;
+ }
else
{
- my $cycle=$nexttimer-time();
- $cycle=1 if $cycle<1;
- $plugin_info{$plugname."_cycle"}=$cycle;
+ plugin_log($plugname, "Logik '$t' wird nicht mehr aufgerufen (alle in time=>... festgelegten Termine sind verstrichen).");
+
+ delete $plugin_info{$plugname.'__'.$t.'_timer'};
}
}
+
+# Es folgt die eigentliche Logik-Engine
+sub execute_logic
+{
+ my ($t, $receive, $ga, $in)=@_; # Logikindex $t, Bustelegramm erhalten auf $ga mit Inhalt $in
+
+ # als erstes definiere das Input-Array fuer die Logik
+ my $input=$in;
+
+ # Array-Fall: bereite Input-Array fuer Logik vor
+ if(!ref $receive)
+ {
+ # wenn ga gesetzt, steht der Input-Wert in $in
+ # wenn receive undefiniert, gibt es keine receive-GA
+ $in=$input=knx_read($receive, 300) if !$ga && $receive;
+ }
+ else
+ {
+ $input=();
+ for my $rec (@{$receive})
+ {
+ my $rec=groupaddress($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};
+ }
+ }
+ }
+
+ return $result;
+}
+
+
# Umgang mit GA-Kurznamen und -Adressen
sub groupaddress
Modified: wiregate/plugin/generic/conf.d/Logikprozessor.conf
===================================================================
--- wiregate/plugin/generic/conf.d/Logikprozessor.conf 2012-05-07 18:51:21 UTC (rev 794)
+++ wiregate/plugin/generic/conf.d/Logikprozessor.conf 2012-05-07 20:46:56 UTC (rev 795)
@@ -21,21 +21,43 @@
# 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).
+ # 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.
- # 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.
+ # Weitere Bemerkungen:
+ # * translate darf nur entweder eine Konstante oder ausf\xFChrbarer 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).
- # 6. Eine einfache UND-Logik mit zwei Eingaengen. Falls ein Telegramm auf einer der beiden receive-GAs empfangen wird,
+ # 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\xFCr diese Logiken vorbesetzt (bitte nicht darauf schreiben, koennte unverhergesehene Auswirkungen
+ # auf andere Logiken haben).
+
+ # 7. Memory-Funktion. Fuer KNX-Ger\xE4te, 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]; }, },
- # 7. Ein komplexerer Fall nur zur Demonstration: hier besteht der Status des Logikprozessors aus mehreren Werten.
+ # 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',
@@ -46,7 +68,19 @@
},
# 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
+ # 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); }, },
@@ -54,5 +88,3 @@
# in einen absoluten Wert umgewandelt
);
-
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|