From 803fe74498ba7d834245a00a2366f23055230a44 Mon Sep 17 00:00:00 2001 From: justme-1968 Date: Tue, 28 May 2019 15:43:47 +0000 Subject: [PATCH] 30_HUEBridge, 31HUEDevice: scenes can be given by name scene dropdown in FHEMWEB show light names for scenes and groups command git-svn-id: https://svn.fhem.de/fhem/trunk@19475 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 3 ++ fhem/FHEM/30_HUEBridge.pm | 83 +++++++++++++++++++++++++++++++-------- fhem/FHEM/31_HUEDevice.pm | 39 ++++++++++++++++-- 3 files changed, 104 insertions(+), 21 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 79da9f66a..0e3ff0a14 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 30_HUEBridge, 31HUEDevice: scenes can be given by name + scene dropdown in FHEMWEB + show light names for scenes and groups - bugfix: 73_GardenaSmartBridge: fix crash then call ARRAY reference - change: 49_SSCam: enhanced log entries of snapinfos with debugactivetoken - change: 49_SSCam: attributes rec/snapemailtxt, rec/snaptelegramtxt may diff --git a/fhem/FHEM/30_HUEBridge.pm b/fhem/FHEM/30_HUEBridge.pm index cae3deb2f..8e708e192 100644 --- a/fhem/FHEM/30_HUEBridge.pm +++ b/fhem/FHEM/30_HUEBridge.pm @@ -89,7 +89,7 @@ HUEBridge_Read($) #ignore keepalive } elsif( $op == 0x01 ) { - my $obj = eval { decode_json($data) }; + my $obj = eval { JSON->new->utf8(0)->decode($data) }; if( $obj ) { Log3 $name, 5, "$name: websocket data: ". Dumper $obj; @@ -190,7 +190,7 @@ HUEBridge_Detect($) my $host = ''; if( defined($ret) && $ret ne '' && $ret =~ m/^[\[{].*[\]}]$/ ) { - my $obj = eval { decode_json($ret) }; + my $obj = eval { JSON->new->utf8(0)->decode($ret) }; Log3 $name, 2, "$name: json error: $@ in $ret" if( $@ ); if( defined($obj->[0]) @@ -481,6 +481,30 @@ HUEBridge_string2array($) my @lights = sort {$a<=>$b} keys(%lights); return \@lights; } +sub +HUEBridge_scene2id($$) +{ + my ($hash,$id) = @_; + $hash = $defs{$hash} if( ref($hash) ne 'HASH' ); + return undef if( !$hash ); + + if( $hash->{helper}{scenes} ) { + return $id if( defined($hash->{helper}{scenes}{$id}) ); + $id = lc($id); + $id =~ s/\((.*)\)$/\\\($1\\\)/; + + foreach my $key ( keys %{$hash->{helper}{scenes}} ) { + my $scene = $hash->{helper}{scenes}{$key}; + + return $key if( lc($key) eq $id ); + return $key if( lc($scene->{name}) =~ m/^$id$/ ); + return $key if( lc("$scene->{name} ($key)") =~ m/^$id$/ ); + #return $key if( $scene->{name} eq $id ); + } + } + + return ''; +} sub HUEBridge_Set($@); sub @@ -663,7 +687,8 @@ HUEBridge_Set($@) return undef; } elsif($cmd eq 'scene') { - return "usage: scene " if( @args != 1 ); + return "usage: scene |" if( @args != 1 ); + $arg = HUEBridge_scene2id($hash, $arg); my $obj = { 'scene' => $arg }; my $result = HUEBridge_Call($hash, undef, "groups/0/action", $obj, 'PUT'); @@ -687,7 +712,7 @@ HUEBridge_Set($@) {"address":"/groups/0/action","method":"PUT", "body":{"scene":"S3"}} ]}' if( 0 || !$args[@args-1] ); my $json = $args[@args-1]; - my $obj = eval { decode_json($json) }; + my $obj = eval { JSON->new->utf8(0)->decode($json) }; if( $@ ) { Log3 $name, 2, "$name: json error: $@ in $json"; return undef; @@ -711,7 +736,7 @@ HUEBridge_Set($@) return "$arg is not a hue schedule number" if( $arg !~ m/^\d+$/ ); my $json = $args[@args-1]; - my $obj = eval { decode_json($json) }; + my $obj = eval { JSON->new->utf8(0)->decode($json) }; if( $@ ) { Log3 $name, 2, "$name: json error: $@ in $json"; return undef; @@ -808,7 +833,7 @@ HUEBridge_Set($@) return "$arg is not a hue sensor number" if( $arg !~ m/^\d+$/ ); my $json = join( ' ', @args[1..@args-1]); - my $decoded = eval { decode_json($json) }; + my $decoded = eval { JSON->new->utf8(0)->decode($json) }; if( $@ ) { Log3 $name, 2, "$name: json error: $@ in $json"; return undef; @@ -873,8 +898,16 @@ HUEBridge_Set($@) return undef; } else { - my $list = "active inactive delete creategroup deletegroup savescene deletescene modifyscene scene createrule updaterule updateschedule enableschedule disableschedule deleterule createsensor deletesensor configsensor setsensor updatesensor deletewhitelist touchlink:noArg checkforupdate:noArg autodetect:noArg autocreate:noArg statusRequest:noArg"; + my $list = "active inactive delete creategroup deletegroup savescene deletescene modifyscene"; + + if( my $scenes = $hash->{helper}{scenes} ) { + $list .= " scene:". join(",", sort map { my $scene = $scenes->{$_}{name}; $scene =~ s/ /#/g ;$scene} keys %{$scenes} ); + } else { + $list .= " scene"; + } $list .= " swupdate:noArg" if( defined($hash->{updatestate}) && $hash->{updatestate} =~ '^2' ); + $list .= " reaterule updaterule updateschedule enableschedule disableschedule deleterule createsensor deletesensor configsensor setsensor updatesensor deletewhitelist touchlink:noArg checkforupdate:noArg autodetect:noArg autocreate:noArg statusRequest:noArg"; + return "Unknown argument $cmd, choose one of $list"; } } @@ -894,6 +927,7 @@ HUEBridge_Get($@) || $cmd eq 'lights') { my $result = HUEBridge_Call($hash, undef, 'lights', undef); return $result->{error}{description} if( $result->{error} ); + $hash->{helper}{lights} = $result; my $ret = ""; foreach my $key ( sort {$a<=>$b} keys %{$result} ) { my $code = $name ."-". $key; @@ -908,6 +942,7 @@ HUEBridge_Get($@) my $result = HUEBridge_Call($hash, undef, 'groups', undef); return $result->{error}{description} if( $result->{error} ); $result->{0} = { name => 'Lightset 0', type => 'LightGroup', lights => ["ALL"] }; + $hash->{helper}{groups} = $result; my $ret = ""; foreach my $key ( sort {$a<=>$b} keys %{$result} ) { my $code = $name ."-G". $key; @@ -916,7 +951,12 @@ HUEBridge_Get($@) $result->{$key}{type} = '' if( !defined($result->{$key}{type}) ); #deCONZ fix $result->{$key}{class} = '' if( !defined($result->{$key}{class}) ); #deCONZ fix $result->{$key}{lights} = [] if( !defined($result->{$key}{lights}) ); #deCONZ fix - $ret .= sprintf( "%2i: %-15s %-15s %-15s %-15s %s\n", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type}, $result->{$key}{class}, join( ",", @{$result->{$key}{lights}} ) ); + $ret .= sprintf( "%2i: %-15s %-15s %-15s %-15s", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type}, $result->{$key}{class} ); + if( !$arg && $hash->{helper}{lights} ) { + $ret .= sprintf( " %s\n", join( ",", map { my $l = $hash->{helper}{lights}{$_}{name}; $l?$l:$_;} @{$result->{$key}{lights}} ) ); + } else { + $ret .= sprintf( " %s\n", join( ",", @{$result->{$key}{lights}} ) ); + } } $ret = sprintf( "%2s %-15s %-15s %-15s %-15s %s\n", "ID", "NAME", "FHEM", "TYPE", "CLASS", "LIGHTS" ) .$ret if( $ret ); return $ret; @@ -924,11 +964,16 @@ HUEBridge_Get($@) } elsif($cmd eq 'scenes') { my $result = HUEBridge_Call($hash, undef, 'scenes', undef); return $result->{error}{description} if( $result->{error} ); + $hash->{helper}{scenes} = $result; my $ret = ""; - foreach my $key ( sort {$a cmp $b} keys %{$result} ) { + foreach my $key ( sort {$result->{$a}{name} cmp $result->{$b}{name}} keys %{$result} ) { $ret .= sprintf( "%-20s %-20s", $key, $result->{$key}{name} ); $ret .= sprintf( "%i %i %i %-40s %-20s", $result->{$key}{recycle}, $result->{$key}{locked},$result->{$key}{version}, $result->{$key}{owner}, $result->{$key}{lastupdated}?$result->{$key}{lastupdated}:'' ) if( $arg && $arg eq 'detail' ); - $ret .= sprintf( " %s\n", join( ",", @{$result->{$key}{lights}} ) ); + if( !$arg && $hash->{helper}{lights} ) { + $ret .= sprintf( " %s\n", join( ",", map { my $l = $hash->{helper}{lights}{$_}{name}; $l?$l:$_;} @{$result->{$key}{lights}} ) ); + } else { + $ret .= sprintf( " %s\n", join( ",", @{$result->{$key}{lights}} ) ); + } } if( $ret ) { my $header = sprintf( "%-20s %-20s", "ID", "NAME" ); @@ -1207,9 +1252,12 @@ HUEBridge_Parse($$) Log3 $name, 4, "parse status message for $name"; #Log3 $name, 5, Dumper $config; + $hash->{helper}{lights} = $config->{lights} if( $config->{lights} ); + $hash->{helper}{groups} = $config->{groups} if( $config->{groups} ); + $hash->{helper}{scenes} = $config->{scenes} if( $config->{scenes} ); + #Log 3, Dumper $config; $config = $config->{config} if( defined($config->{config}) ); - HUEBridge_fillBridgeInfo($hash, $config); $hash->{zigbeechannel} = $config->{zigbeechannel}; @@ -1414,7 +1462,8 @@ HUEBridge_ProcessResponse($$) return undef; } -sub HUEBridge_Register($) +sub +HUEBridge_Register($) { my ($hash) = @_; @@ -1517,7 +1566,7 @@ HUEBridge_HTTP_Call($$$;$) return undef; } - my $decoded = eval { decode_json($ret) }; + my $decoded = eval { JSON->new->utf8(0)->decode($ret) }; Log3 $name, 2, "$name: json error: $@ in $ret" if( $@ ); return HUEBridge_ProcessResponse($hash, $decoded); @@ -1577,7 +1626,7 @@ HUEBridge_HTTP_Call2($$$$;$) return undef; } - my $json = eval { decode_json($data) }; + my $json = eval { JSON->new->utf8(0)->decode($data) }; Log3 $name, 2, "$name: json error: $@ in $data" if( $@ ); return undef if( !$json ); @@ -1627,7 +1676,7 @@ HUEBridge_dispatch($$$;$) my $queryAfterSet = AttrVal( $name,'queryAfterSet', 1 ); if( !$json ) { - $json = eval { decode_json($data) } if( !$json ); + $json = eval { JSON->new->utf8(0)->decode($data) } if( !$json ); Log3 $name, 2, "$name: json error: $@ in $data" if( $@ ); } return undef if( !$json ); @@ -1651,7 +1700,7 @@ HUEBridge_dispatch($$$;$) if( $hash == $param->{chash} ) { if( !defined($type) ) { - HUEBridge_Parse($hash,$json->{config}); + HUEBridge_Parse($hash,$json); if( defined($json->{sensors}) ) { my $sensors = $json->{sensors}; @@ -1971,7 +2020,7 @@ HUEBridge_Attr($$$) The lights are given as a comma sparated list of fhem device names or bridge light numbers.
  • modifyscene <id> <light> <light-args>
    Modifys the given scene in the bridge.
  • -
  • scene <id>
    +
  • scene <id>|&lr;name>
    Recalls the scene with the given id.
  • updateschedule <id> <attributes json>
    updates the given schedule in the bridge with <attributes json>
  • diff --git a/fhem/FHEM/31_HUEDevice.pm b/fhem/FHEM/31_HUEDevice.pm index 82aca7bba..4c986c0bd 100644 --- a/fhem/FHEM/31_HUEDevice.pm +++ b/fhem/FHEM/31_HUEDevice.pm @@ -660,9 +660,11 @@ HUEDevice_Set($@) return fhem( "set $hash->{IODev}{NAME} deletescene $aa[1]" ); } elsif( $cmd eq 'scene' ) { - return "usage: scene " if( @args != 1 ); + return "usage: scene |" if( @args != 1 ); + my $arg = $args[0]; + $arg = HUEBridge_scene2id($hash->{IODev}, $arg) if( $hash->{IODev} && $hash->{IODev}{TYPE} eq 'HUEBridge' ); - my $obj = {'scene' => $aa[1]}; + my $obj = {'scene' => $arg}; $hash->{helper}->{update} = 1; my $result = HUEDevice_ReadFromServer($hash,"$hash->{ID}/action",$obj); return $result->{error}{description} if( $result->{error} ); @@ -852,9 +854,26 @@ HUEDevice_Set($@) $list .= " rename"; - $list .= " savescene deletescene" if( $hash->{helper}->{devtype} eq 'G' ); + if( $hash->{helper}->{devtype} eq 'G' ) { + $list .= " savescene deletescene"; + } + + if( my $scenes = $hash->{IODev}{helper}{scenes} ) { + local *containsOneOfMyLights = sub($) { + return 1 if( !defined($hash->{helper}{lights}) ); + + my( $lights ) = @_; + + foreach my $light (@{$lights}) { + return 1 if( defined($hash->{helper}{lights}{$light}) ); + } + return 0; + }; + $list .= " scene:". join(",", sort grep { defined } map { if( !containsOneOfMyLights($scenes->{$_}{lights}) ) { undef; } else { my $scene = $scenes->{$_}{name}; $scene =~ s/ /#/g; $scene} } keys %{$scenes} ); + } else { + $list .= " scene"; + } } - $list .= " scene" if( $hash->{helper}->{devtype} eq 'G' ); return SetExtensions($hash, $list, $name, @aa); } @@ -1139,9 +1158,21 @@ HUEDevice_Parse($$) $hash->{uniqueid} = $result->{uniqueid} if( defined($result->{uniqueid}) ); if( $hash->{helper}->{devtype} eq 'G' ) { + + #if( !defined($attr{$name}{subType}) && $hash->{type} ) { + # if( $hash->{type} eq 'Room' ) { + # $attr{$name}{subType} = 'room'; + # + # } elsif( $hash->{type} eq 'LightGroup' ) { + # $attr{$name}{subType} = 'lightgroup'; + # } + #} + if( $result->{lights} ) { + $hash->{helper}{lights} = {map {$_=>1} @{$result->{lights}}}; $hash->{lights} = join( ",", sort { $a <=> $b } @{$result->{lights}} ); } else { + $hash->{helper}{lights} = {}; $hash->{lights} = ''; }