From 3085f8972f025bf26a15a19761be2371770e55e7 Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Wed, 19 Sep 2012 07:29:38 +0000
Subject: [PATCH] Structure changes by Tobias
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@1869 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
FHEM/98_structure.pm | 172 ++++++++++++++++++++++++++++++++++++++++++-
docs/commandref.html | 59 +++++++++++----
2 files changed, 216 insertions(+), 15 deletions(-)
diff --git a/FHEM/98_structure.pm b/FHEM/98_structure.pm
index 12e1ffe45..9a3d8371e 100755
--- a/FHEM/98_structure.pm
+++ b/FHEM/98_structure.pm
@@ -4,6 +4,8 @@ package main;
use strict;
use warnings;
+#use Data::Dumper;
+
#####################################
sub
@@ -13,9 +15,11 @@ structure_Initialize($)
$hash->{DefFn} = "structure_Define";
$hash->{UndefFn} = "structure_Undef";
-
+ $hash->{NotifyFn} = "structure_Notify";
$hash->{SetFn} = "structure_Set";
$hash->{AttrFn} = "structure_Attr";
+ $hash->{AttrList} = "clientstate_priority clientstate_behavior:relative,absolute";
+
addToAttrList("structexclude");
my %ahash = ( Fn=>"CommandAddStruct",
@@ -43,6 +47,7 @@ structure_Define($$)
my $stype = shift(@a);
addToAttrList($stype);
+ addToAttrList($stype . "_map");
$hash->{ATTR} = $stype;
my %list;
@@ -70,6 +75,171 @@ structure_Undef($$)
return undef;
}
+#############################
+# returns the unique keys of the given array
+# @my_array = ("one","two","three","two","three");
+# print join(" ", @my_array), "\n";
+# print join(" ", uniq(@my_array)), "\n";
+
+sub uniq {
+ return keys %{{ map { $_ => 1 } @_ }};
+}
+
+
+#############################
+sub structure_Notify($$)
+{
+ my ($hash, $dev) = @_;
+ #Log 1, Dumper($hash);
+ my $me = $hash->{NAME};
+ my $devmap = $hash->{ATTR}."_map";
+
+ # lade das Verhalten, Standard ist absolute
+ my $behavior = AttrVal($me,"clientstate_behavior", "absolute");
+ my @clientstate;
+
+ return "" if($attr{$me} && $attr{$me}{disable});
+
+ #pruefen ob Devices welches das notify ausgeloest hat Mitglied dieser
+ # Struktur ist
+ return "" if (!$hash->{CONTENT}->{$dev->{NAME}});
+
+ # hier nur den Struktur-Status anpassen wenn
+ # a) behavior=absolute oder
+ # b) behavior=relative UND das Attr clientstate_priority gefaellt ist
+ my @structPrio = split(" ", $attr{$me}{clientstate_priority})
+ if($attr{$me}{clientstate_priority});
+ return "" if (!@structPrio && $behavior eq "relative");
+
+ # assoziatives Array aus Prioritaetsliste aufbauen
+ # Bsp: Original: "On|An Off|Aus"
+ # wobei der erste Wert der "Oder"-Liste als Status der Struktur uebernommen
+ # wird hier also On oder Off
+ # priority[On]=0
+ # priority[An]=0
+ # priority[Off]=1
+ # priority[Aus]=1
+ my %priority;
+ my (@priority, @foo);
+ for (my $i=0; $i<@structPrio; $i++) {
+ @foo = split(/\|/, $structPrio[$i]);
+ for (my $j=0; $j<@foo;$j++) {
+ $priority{$foo[$j]} = $i+1;
+ $priority[$i+1]=$foo[0];
+ }
+ }
+ undef @foo;
+ undef @structPrio;
+ #Log 1, Dumper(%priority) . "\n";
+
+ $hash->{INSET} = 1;
+
+ my $minprio = 99999;
+ my $devstate;
+
+ #ueber jedes Device das zu dieser Struktur gehoert
+ foreach my $d (sort keys %{ $hash->{CONTENT} }) {
+ next if(!$defs{$d});
+ if($defs{$d}{INSET}) {
+ Log 1, "ERROR: endless loop detected for $d in " . $hash->{NAME};
+ next;
+ }
+
+ # wenn zum Device das "structexclude" gesetzt ist, wird dieses nicht
+ # beruecksichtigt
+ if($attr{$d} && $attr{$d}{structexclude}) {
+ my $se = $attr{$d}{structexclude};
+ next if($hash->{NAME} =~ m/$se/);
+ }
+
+
+ # Status des Devices gemaess den Regeln des gesetztes StrukturAttr
+ # umformatieren
+ if ($attr{$d}{$devmap}) {
+ my @gruppe = split(" ", $attr{$d}{$devmap});
+ my @value;
+ for (my $i=0; $i<@gruppe; $i++) {
+ @value = split(":", $gruppe[$i]);
+ if(@value == 1) {
+ # nur das zu lesende Reading ist angegeben, zb. bei 1wire Modul
+ # OWSWITCH
+ #Bsp: A --> nur Reading A gehuert zur Struktur
+ #Bsp: A B --> Reading A und B gehuert zur Struktur
+ $devstate = ReadingsVal($d, $value[0], undef);
+ push(@clientstate, $devstate);
+ } elsif(@value == 2) {
+ # zustand wenn der Status auf dem in der Struktur definierten
+ # umdefiniert werden muss
+ # bsp: on:An
+ if($devstate eq $value[0]){
+ $devstate = $value[1];
+ push(@clientstate, $devstate);
+ $i=99999;
+ }
+ } elsif(@value == 3) {
+ # Das zu lesende Reading wurde mit angegeben:
+ # Reading:OriginalStatus:NeuerStatus wenn zb. ein Device mehrere
+ # Readings abbildet, zb. 1wire DS2406, DS2450 Bsp: A:Zu.:Geschlossen
+ $devstate = ReadingsVal($d, $value[0], undef);
+ if($devstate eq $value[1]){
+ $devstate = $value[2];
+ push(@clientstate, $devstate);
+ # $i=99999; entfernt, wenn Device mehrere Ports/Readings abbildet
+ # wird beim ersten Auftreten sonst nicht weiter geprueft
+ }
+ }
+ # Log 1, "Dev: ".$d." Anzahl: ".@value." Value:".$value[0]." devstate:
+ # ".$devstate;
+ $minprio = $priority{$devstate}
+ if($devstate &&
+ $priority{$devstate} &&
+ $priority{$devstate} < $minprio);
+ }
+ } else {
+ # falls kein mapping im Device angegeben wurde
+ $devstate = ReadingsVal($d, "state", undef);
+ $minprio = $priority{$devstate}
+ if($devstate &&
+ $priority{$devstate} &&
+ $priority{$devstate} < $minprio);
+ push(@clientstate, $devstate);
+ }
+
+ #besser als 1 kann minprio nicht werden
+ last if($minprio == 1);
+ } #foreach
+
+ @clientstate = uniq(@clientstate);# eleminiere alle Dubletten
+
+ #ermittle Endstatus
+ my $newState;
+ if($behavior eq "absolute"){
+ # wenn absolute, dann gebe undefinierten Status aus falls die Clients
+ # unterschiedliche Status' haben
+ if(@clientstate > 1) { $newState = "undefined";}
+ else { $newState = $clientstate[0];}
+ } elsif($behavior eq "relative" && $minprio < 99999) {
+ $newState = $priority[$minprio];
+ } else {
+ $newState = "undefined";
+ }
+
+
+ #eigenen Status jetzt setzen, nur wenn abweichend
+ if($hash->{STATE} ne $newState) {
+ Log 3, "Update structure '" .$me . "' to " . $newState .
+ " because device '" .$dev->{NAME}. "' has changed";
+ $hash->{STATE} = $newState;
+ readingsBeginUpdate($hash);
+ readingsUpdate($hash, "state", $newState);
+ readingsEndUpdate($hash, 1);
+ }
+ #Log 1, "devstate: ".$devstate." - minprio final: " . $minprio . "\n";
+ #Log 1, Dumper(%priority);
+ delete($hash->{INSET});
+
+ undef;
+}
#####################################
sub
diff --git a/docs/commandref.html b/docs/commandref.html
index 72baf31fe..e026eebd1 100644
--- a/docs/commandref.html
+++ b/docs/commandref.html
@@ -5385,6 +5385,7 @@ To send the data, both send or write could be used.
Notice: All links are relative to http://hostname:8083/fhem
.
+
define <name> structure <struct_type> <dev1> <dev2> ...