From 2d700a705b31a4f2bbfb2e405cf9cc5a44e3eb66 Mon Sep 17 00:00:00 2001 From: justme-1968 Date: Mon, 31 Jan 2022 10:04:50 +0000 Subject: [PATCH] 30_HUEBridge: added get v2effects & set v2json 31_HUEDevice: added get v2effects & set v2scene git-svn-id: https://svn.fhem.de/fhem/trunk@25600 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/30_HUEBridge.pm | 114 ++++++++++++++++++++++++++++---------- fhem/FHEM/31_HUEDevice.pm | 99 ++++++++++++++++++++++++++++----- 3 files changed, 174 insertions(+), 41 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 735f43167..f71dcd6a2 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # 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: added get v2effects & set v2json + - feature: 31_HUEDevice: added get v2effects & set v2scene - change: 93_DbRep: new sqlCmdHistory params, change optimizeTables fix MySQL dump clientSide, some minor fixes - new: 70_ESCVP21net.pm: new module for Epson Beamer LAN control diff --git a/fhem/FHEM/30_HUEBridge.pm b/fhem/FHEM/30_HUEBridge.pm index d7ac8e9aa..576d978e0 100644 --- a/fhem/FHEM/30_HUEBridge.pm +++ b/fhem/FHEM/30_HUEBridge.pm @@ -1144,6 +1144,12 @@ HUEBridge_Set($@) readingsSingleUpdate($hash, 'state', 'inactive', 1 ); return undef; + } elsif($cmd eq 'refreshv2resources' ) { + return "$name: v2 api not supported" if( !$hash->{has_v2_api} ); + HUEBridge_refreshv2resources($hash, 1); + + return "done"; + } elsif($cmd eq 'v2json' ) { return "usage: $cmd " if( !@params ); @@ -1220,6 +1226,7 @@ HUEBridge_Set($@) return; } elsif($cmd eq 'v2scene' ) { + return "usage: $cmd " if( @args != 1 || $args[0] eq '?' ); my $params = { url => "https://$hash->{host}/clip/v2/resource/scene/$arg", method => 'PUT', @@ -1285,7 +1292,7 @@ HUEBridge_Set($@) $list .= " createrule updaterule updateschedule enableschedule disableschedule deleterule createsensor deletesensor configsensor setsensor updatesensor deletewhitelist touchlink:noArg checkforupdate:noArg autodetect:noArg autocreate:noArg statusRequest:noArg"; if( $hash->{has_v2_api} ) { - $list .= " v2scene"; + $list .= " refreshv2resources v2json v2scene "; } return "Unknown argument $cmd, choose one of $list"; @@ -1301,13 +1308,26 @@ HUEBridge_V2IdOfV1Id($$$) return "undef" if( !$type ); return "undef" if( !$hash->{has_v2_api} ); - foreach my $entry ( values %{$hash->{helper}{resource}{by_id}} ) { - next if( !$entry->{id_v1} ); - next if( !$entry->{type} ); - next if( $entry->{id_v1} ne $id ); - next if( $entry->{type} ne $type ); + foreach my $resource ( values %{$hash->{helper}{resource}{by_id}} ) { + next if( !$resource->{id_v1} ); + next if( !$resource->{type} ); + next if( $resource->{id_v1} ne $id ); + next if( $resource->{type} ne $type ); - return $entry->{id}; + return $resource->{id}; + } + + return undef; +} +sub +HUEBridge_GetResource($$) +{ + my ($hash, $id) = @_; + return undef if( !$hash->{has_v2_api} ); + return undef if( !$id ); + + if( my $resource = $hash->{helper}{resource}{by_id}{$id} ) { + return $resource; } return undef; @@ -1366,20 +1386,20 @@ HUEBridge_Get($@) $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; - my $fhem_name = ''; + foreach my $id ( sort {$a<=>$b} keys %{$result} ) { + my $code = $name ."-G". $id; + my $fhem_name; $fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) ); $fhem_name = ' (ignored)' if( !$fhem_name && $hash->{helper}{ignored}{$code} ); - $fhem_name = "" if( !$fhem_name ); - $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", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type}, $result->{$key}{class} ); + $fhem_name = '' if( !$fhem_name ); + $result->{$id}{type} = '' if( !defined($result->{$id}{type}) ); #deCONZ fix + $result->{$id}{class} = '' if( !defined($result->{$id}{class}) ); #deCONZ fix + $result->{$id}{lights} = [] if( !defined($result->{$id}{lights}) ); #deCONZ fix + $ret .= sprintf( "%2i: %-15s %-15s %-15s %-15s", $id, $result->{$id}{name}, $fhem_name, $result->{$id}{type}, $result->{$id}{class} ); if( !$arg && $hash->{helper}{lights} ) { - $ret .= sprintf( " %s\n", join( ",", map { my $l = $hash->{helper}{lights}{$_}{name}; $l?$l:$_;} @{$result->{$key}{lights}} ) ); + $ret .= sprintf( " %s\n", join( ",", map { my $l = $hash->{helper}{lights}{$_}{name}; $l?$l:$_;} @{$result->{$id}{lights}} ) ); } else { - $ret .= sprintf( " %s\n", join( ",", @{$result->{$key}{lights}} ) ); + $ret .= sprintf( " %s\n", join( ",", @{$result->{$id}{lights}} ) ); } } $ret = sprintf( "%2s %-15s %-15s %-15s %-15s %s\n", "ID", "NAME", "FHEM", "TYPE", "CLASS", "LIGHTS" ) .$ret if( $ret ); @@ -1521,12 +1541,6 @@ HUEBridge_Get($@) } elsif($cmd eq 'ignored' ) { return join( "\n", sort keys %{$hash->{helper}{ignored}} ); - } elsif($cmd eq 'refreshv2resources' ) { - return "$name: v2 api not supported" if( !$hash->{has_v2_api} ); - HUEBridge_refreshv2resources($hash, 1); - - return "done"; - } elsif($cmd eq 'v2resourcetypes' ) { return "$name: v2 api not supported" if( !$hash->{has_v2_api} ); my %result; @@ -1581,12 +1595,40 @@ HUEBridge_Get($@) } elsif($cmd eq 'v2scenes' ) { return "$name: v2 api not supported" if( !$hash->{has_v2_api} ); my $ret; - foreach my $entry ( values %{$hash->{helper}{resource}{by_id}} ) { + foreach my $entry ( sort {$a->{group}{rid} cmp $b->{group}{rid}} values %{$hash->{helper}{resource}{by_id}} ) { next if( $entry->{type} ne 'scene' ); - $ret .= sprintf( "%-36s %-25s %-10s", $entry->{id}, $entry->{metadata}{name}, HUEBridge_nameOfResource($hash,$entry->{group}{rid}) ); - $ret .= "\n"; + my $room = HUEBridge_GetResource($hash,$entry->{group}{rid}); + my(undef, $t, $id) = split( '/', $room->{id_v1} ); + my $code = $name ."-G". $id; + my $fhem_name; + $fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) ); + $fhem_name = ' (ignored)' if( !$fhem_name && $hash->{helper}{ignored}{$code} ); + $fhem_name = '' if( !$fhem_name ); + $ret .= sprintf( "%-36s %-25s %s (%s", $entry->{id}, $entry->{metadata}{name}, HUEBridge_nameOfResource($hash,$entry->{group}{rid}), $fhem_name ); + if( $arg && $entry->{actions}) { + $ret .= sprintf( ": %s\n", join( ",", map { my $l = HUEBridge_nameOfResource($hash,$_->{target}{rid}); $l?$l:$_;} @{$entry->{actions}} ) ); + } + $ret .= ")\n"; } - $ret = sprintf( "%-36s %-25s %-15s %s\t%s\n", "ID", "NAME", "ROOM", "", "" ) .$ret if( $ret ); + $ret = sprintf( "%-36s %-21s %s\n", "ID", "NAME", "for GROUP" ) .$ret if( $ret ); + return $ret; + + } elsif($cmd eq 'v2effects' ) { + return "$name: v2 api not supported" if( !$hash->{has_v2_api} ); + return "usage: $cmd []" if( $arg && $arg eq '?' ); + my $ret; + foreach my $entry ( values %{$hash->{helper}{resource}{by_id}} ) { + next if( !$entry->{effects} ); + next if( $arg && $arg ne $entry->{id} ); + my(undef, $t, $id) = split( '/', $entry->{id_v1} ); + my $code = $name ."-". $id; + my $fhem_name = ''; + $fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) ); + $ret .= sprintf( "%-36s %-2s %-15s %s:", $entry->{id}, $id, $fhem_name, $entry->{metadata}{name} ) if( $hash->{CL} ); + $ret .= join( ',', @{$entry->{effects}{effect_values}} ); + $ret .= "\n" if( $hash->{CL} ); + } + $ret = sprintf( "%-36s %-2s %-15s %s\n", "ID", "V1", "FEHM", "NAME", ). $ret if( $ret && $hash->{CL} ); return $ret; } else { @@ -1596,7 +1638,7 @@ HUEBridge_Get($@) } if( $hash->{has_v2_api} ) { - $list .= " v2devices v2resource v2resourcetypes v2scenes"; + $list .= " v2devices v2effects v2resource v2resourcetypes v2scenes"; } return "Unknown argument $cmd, choose one of $list"; @@ -2418,6 +2460,22 @@ HUEBridge_dispatch($$$;$) Log3 $name, 4, "$name: found $count new resources"; HUEBridge_Autocreate($hash) if( $count ); + foreach my $resource ( values %{$hash->{helper}{resource}{by_id}} ) { + next if( !$resource->{type} ); + next if( !$resource->{id_v1} ); + if( $resource->{type} eq 'device' ) { + my(undef, $t, $id) = split( '/', $resource->{id_v1} ); + my $code; + $code = $name ."-". $id if( $t eq 'lights' ); + $code = $name ."-S". $id if( $t eq 'sensors' ); + $code = $name ."-G". $id if( $t eq 'groups' ); + next if( !$code ); + if( my $chash = $modules{HUEDevice}{defptr}{$code} ) { + $chash->{v2_id} = $resource->{id}; + } + } + } + return undef; } elsif( defined($type) && $type eq 'event' ) { diff --git a/fhem/FHEM/31_HUEDevice.pm b/fhem/FHEM/31_HUEDevice.pm index e38fd9b6b..67934e35c 100644 --- a/fhem/FHEM/31_HUEDevice.pm +++ b/fhem/FHEM/31_HUEDevice.pm @@ -800,10 +800,10 @@ HUEDevice_SetParam($$@) } elsif( $cmd eq 'v2effect' ) { my $hash = $defs{$name}; - my $shash = $hash->{IODev}; - my $id = HUEBridge_V2IdOfV1Id( $shash, 'light', "/lights/$hash->{ID}" ); + my $iohash = $hash->{IODev}; + my $id = HUEBridge_V2IdOfV1Id( $iohash, 'light', "/lights/$hash->{ID}" ); - HUEBridge_Set( $shash, $shash->{NAME}, $cmd, $id, $value ); + HUEBridge_Set( $iohash, $iohash->{NAME}, $cmd, $id, $value ); $obj->{'on'} = JSON::true; @@ -863,7 +863,7 @@ HUEDevice_Set($@) return fhem( "set $hash->{IODev}{NAME} deletescene $aa[1]" ); } elsif( $cmd eq 'scene' ) { - return "usage: scene |" if( !@args ); + return "usage: $cmd |" if( !@args || $args[0] eq '?' ); my $arg = join( ' ', @args ); my $deConz; if( $hash->{IODev} ) { @@ -898,10 +898,30 @@ HUEDevice_Set($@) HUEDevice_GetUpdate( $hash ); } return undef; + + } elsif( $cmd eq 'v2scene' ) { + return "<$name has no IODEV>" if( !$hash->{IODev} ); + return "$name: v2 api not supported" if( !$hash->{IODev} || !$hash->{IODev}{has_v2_api} ); + return "usage: $cmd " if( !@args || $args[0] eq '?' ); + + my $arg = join( ' ', @args ); + + my $v2id; + if( $arg =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/ ) { + $v2id = $1; + + return "no v2 scene with id $v2id found" if( !HUEBridge_nameOfResource( $hash->{IODev}, $v2id ) ); + + } else { + return "$arg is not a v2 scene id"; + + } + + return CommandSet( $hash->{IODev}, "$hash->{IODev}->{NAME} v2scene $v2id" ); } } elsif( $hash->{helper}->{devtype} eq 'S' ) { - my $shash = $hash->{IODev}; + my $iohash = $hash->{IODev}; my $id = $hash->{ID}; $id = $1 if( $id =~ m/^S(\d.*)/ ); @@ -919,12 +939,12 @@ HUEDevice_Set($@) if( $args[0] eq 'setsensor' || $args[0] eq 'configsensor' ) { $type = shift @args; } - return HUEBridge_Set( $shash, $shash->{NAME}, $type, $id, @args ); + return HUEBridge_Set( $iohash, $iohash->{NAME}, $type, $id, @args ); return undef; } elsif( @match = grep { $cmd eq $_ } keys %{($hash->{helper}{setList}{cmds}?$hash->{helper}{setList}{cmds}:{})} ) { - return HUEBridge_Set( $shash, $shash->{NAME}, 'setsensor', $id, $hash->{helper}{setList}{cmds}{$match[0]} ); + return HUEBridge_Set( $iohash, $iohash->{NAME}, 'setsensor', $id, $hash->{helper}{setList}{cmds}{$match[0]} ); } elsif( $entries = $hash->{helper}{setList}{regex} ) { foreach my $entry (@{$entries}) { @@ -944,13 +964,13 @@ HUEDevice_Set($@) $json =~ s/\$2/$VALUE2/; $json =~ s/\$3/$VALUE3/; } - return HUEBridge_Set( $shash, $shash->{NAME}, 'setsensor', $id, $json ); + return HUEBridge_Set( $iohash, $iohash->{NAME}, 'setsensor', $id, $json ); } } } elsif( @match = grep { $cmd eq $_ } keys %{($hash->{helper}{configList}{cmds}?$hash->{helper}{configList}{cmds}:{})} ) { - return HUEBridge_Set( $shash, $shash->{NAME}, 'configsensor', $id, $hash->{helper}{configList}{cmds}{$match[0]} ); + return HUEBridge_Set( $iohash, $iohash->{NAME}, 'configsensor', $id, $hash->{helper}{configList}{cmds}{$match[0]} ); } elsif( $entries = $hash->{helper}{configList}{regex} ) { foreach my $entry (@{$entries}) { @@ -970,7 +990,7 @@ HUEDevice_Set($@) $json =~ s/\$2/$VALUE2/; $json =~ s/\$3/$VALUE3/; } - return HUEBridge_Set( $shash, $shash->{NAME}, 'configsensor', $id, $json ); + return HUEBridge_Set( $iohash, $iohash->{NAME}, 'configsensor', $id, $json ); } } @@ -1215,6 +1235,48 @@ HUEDevice_Set($@) } + if( $hash->{IODev} && $hash->{IODev}{has_v2_api} ) { + my $iohash = $hash->{IODev}; + my $id = $hash->{ID}; $id = $1 if( $id =~ m/^G(\d.*)/ ); + my $v2id = HUEBridge_V2IdOfV1Id( $iohash, 'room', "/groups/$id" ); + $v2id = HUEBridge_V2IdOfV1Id( $iohash, 'zone', "/groups/$id" ) if( !$v2id ); + $v2id = HUEBridge_V2IdOfV1Id( $iohash, 'group', "/groups/$id" ) if( !$v2id ); + #$v2id = HUEBridge_V2IdOfV1Id( $iohash, 'grouped_light', "/groups/$id" ) if( !$v2id ); + + my $scenes = ''; + if( my $resources = $iohash->{helper}{resource}{by_id} ) { + foreach my $scene ( values %{$resources} ) { + next if( !$scene->{type} ); + next if( $scene->{type} ne 'scene' ); + local *containsOneOfMyLights = sub($) { + return 1 if( !defined($hash->{helper}{lights}) ); + + my( $scene ) = @_; + + + foreach my $light (keys %{$hash->{helper}{lights}}) { + my $id = HUEBridge_V2IdOfV1Id( $iohash, 'light', "/lights/$light" ); + foreach my $action (@{$scene->{actions}}) { + return 1 if( $id eq $action->{target}{rid} ); + } + } + return 0; + }; + + next if( !$v2id ); #fixme: optimize! + next if( $v2id ne $scene->{group}{rid} ); + #next if( !containsOneOfMyLights($scene) ); + + $scenes .= ',' if( $scenes ); + $scenes .= $scene->{metadata}{name}; + $scenes .= " [$scene->{id}]"; + + } + $scenes =~ s/ /#/g; + $list .= " v2scene:$scenes" if( $scenes ); + } + } + return SetExtensions($hash, $list, $name, @aa); } @@ -1364,6 +1426,7 @@ HUEDevice_Get($@) ($r,$g,$b) = HUEDevice_xyYtorgb($x,$y,$Y); } return sprintf( "%02x%02x%02x", $r+0.5, $g+0.5, $b+0.5 ); + } elsif ( $cmd eq "startup" ) { my $result = IOWrite($hash,undef,$hash->{NAME},$hash->{ID}); return $result->{error}{description} if( $result->{error} ); @@ -1371,6 +1434,14 @@ HUEDevice_Get($@) return "$result->{config}{startup}{mode}\t$result->{config}{startup}{configured}"; return Dumper $result->{config}{startup}; + } elsif ( $cmd eq "v2effects" ) { + return "<$name has no IODEV>" if( !$hash->{IODev} ); + return "$name: v2 api not supported" if( !$hash->{IODev} || !$hash->{IODev}{has_v2_api} ); + + my $v2id = HUEBridge_V2IdOfV1Id( $hash->{IODev}, 'light', "/lights/$hash->{ID}" ); + return '' if( !$v2id ); + return CommandGet( $hash, "$hash->{IODev}->{NAME} v2effects $v2id" ); + } elsif ( $cmd eq "devStateIcon" ) { return HUEDevice_devStateIcon($hash); } @@ -1388,6 +1459,8 @@ HUEDevice_Get($@) $list .= " startup:noArg"; } + $list .= " v2effects" if( !$hash->{helper}->{devtype} && $hash->{IODev} && $hash->{IODev}{has_v2_api} ); + return "Unknown argument $cmd" if( !$list ); return "Unknown argument $cmd, choose one of $list"; @@ -1874,7 +1947,7 @@ HUEDevice_Parse($$) } elsif( $type eq '03' ) { $readings{eventtype} = 'long_release'; - } + } } } @@ -2080,8 +2153,8 @@ HUEDevice_Parse($$) if( $on != $hash->{helper}{on} ) {readingsBulkUpdate($hash,"onoff",0);} } - $readings{dynamics_status} = 'none' if( !$on && defined($hash->{helper}{dynamics_status}) && !defined($readings{dynamics_status}) ); - $readings{v2effect} = 'no_effect' if( !$on && defined($hash->{helper}{v2effect}) && !defined($readings{v2effect}) ); + $readings{dynamics_status} = 'none' if( !$on && $hash->{helper}{dynamics_status} && !defined($readings{dynamics_status}) ); + $readings{v2effect} = 'no_effect' if( !$on && $hash->{helper}{v2effect} && !defined($readings{v2effect}) ); if( $pct != $hash->{helper}{pct} ) {readingsBulkUpdate($hash,"pct", $pct);} #if( $pct != $hash->{helper}{pct} ) {readingsBulkUpdate($hash,"level", $pct . ' %');}