From 24e33dfc10e38e294832d6a90de1187162f08ca6 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@1869 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/98_structure.pm | 172 +++++++++++++++++++++++++++++++++++++- fhem/docs/commandref.html | 59 +++++++++---- 2 files changed, 216 insertions(+), 15 deletions(-) diff --git a/fhem/FHEM/98_structure.pm b/fhem/FHEM/98_structure.pm index 12e1ffe45..9a3d8371e 100755 --- a/fhem/FHEM/98_structure.pm +++ b/fhem/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/fhem/docs/commandref.html b/fhem/docs/commandref.html index 72baf31fe..e026eebd1 100644 --- a/fhem/docs/commandref.html +++ b/fhem/docs/commandref.html @@ -5385,6 +5385,7 @@ To send the data, both send or write could be used.<br> Notice: All links are relative to <code>http://hostname:8083/fhem</code>. </ul> <br><br> +</ul> <a name="USF1000"></a> <h3>USF1000</h3> @@ -7921,6 +7922,7 @@ This module supports Samsung TV devices with few commands. It's developed and te <b>Get</b><br> <ul>N/A</ul><br> +</ul> <a name="NetIO230B"></a> @@ -10498,29 +10500,27 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433 </ul> - <a name="structure"></a> <h3>structure</h3> <ul> <br> - <a name="structuredefine"></a> <b>Define</b> <ul> <code>define <name> structure <struct_type> <dev1> <dev2> ...</code> <br><br> - - The structure device is used to organize/structure a devices in order to + The structure device is used to organize/structure devices in order to set groups of them at once (e.g. switching everything off in a house).<br> The list of attached devices can be modified through the addstruct / delstruct commands. Each attached device will get the attribute <struct_type>=<name><br> when it is added to the list, and the attribute will be deleted if the device is deleted from the structure. - Exception to this are the attributes room and alias. The structure devices - can also be added to a structure, e.g. you can have a building consisting - of levels which consists of rooms of devices. <br> + The structure devices can also be added to a structure, e.g. you can have + a building consisting of levels which consists of rooms of devices. + <br> + Example:<br> <ul> <li>define kitchen structure room lamp1 lamp2</li> @@ -10529,9 +10529,45 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433 <li>define house structure building kitchen living</li> <li>set house off</li> </ul> - </ul> - <br> + <br> + The backward propagated status change from the devices to this structure + works in two different ways. + <br>Attribute clientstate_behavior<br> + <li>absolute</li> + <ul> + The structure status will changed to the common device status of all defined devices + to this structure if all devices are identical. Otherwise the structure status is "undefined". + </ul> + <li>relative</li> + <ul> + You have to set the attribute "clientstate_priority" with all states of + the defined devices to this structure in descending order. Each group are + delemited by space. Each entry of one group are delimited by "pipe" + </ul> + <br>Example:<br> + <ul> + <li>attr kittchen clientstate_behavior relative</li> + <li>attr kittchen clientstate_priority An|On|on Aus|Off|off</li> + <li>attr house clientstate_priority Any_On|An All_Off|Aus</li> + </ul> + <br> + To group more devices from different types of devices you can define + a clientstate redefining on each device. For example the Reading "A" of device door + is "open" or "closed" and the state of device lamp1 should redefine from + "on" to "An" and "off" to "Aus" + <br>Example:<br> + <ul> + <li>define door OWSWITCH <ROMID></li> + <li>define lamp1 dummy</li> + <li>attr lamp1 cmdlist on off</li> + <li>define kitchen structure struct_kitchen lamp1 door</li> + <li>attr kittchen clientstate_priority An|on OK|Aus|off</li> + <li>attr lamp1 struct_kitchen on:An off:Aus</li> + <li>attr door struct_kitchen A:open:on A:closed:off</li> + </ul> + + <br> <a name="structureset"></a> <b>Set</b> <ul> @@ -10540,15 +10576,12 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433 matches (as a regexp) the name of the current structure. </ul> <br> - <a name="structureget"></a> <b>Get</b> <ul> get is not supported through a structure device. </ul> <br> - - <a name="structureattr"></a> <b>Attributes</b> <ul> @@ -10556,10 +10589,8 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433 exclude the device from set operations, see the set command above.</li> </ul> <br> - </ul> - <a name="watchdog"></a> <h3>watchdog</h3> <ul>