mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 16:59:18 +00:00
HUEbridge: added support for HUE scenes
(get: scenes; set: savescene, modifyscene, scene) new unified syntax for multiple lights in group and scene commands don't query status after set: use bridge response instead added queryAfterSet attribute HUEDevice: added support for HUE scenes (set: savescene, scene) new unified syntax for multiple lights in lights command LightScene: support HUE scenes added asyncDelay attribute git-svn-id: https://svn.fhem.de/fhem/trunk@9451 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
5176777a28
commit
9e66b8ba85
10
fhem/CHANGED
10
fhem/CHANGED
@ -1,5 +1,15 @@
|
||||
# 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: HUEbridge: added support for HUE scenes
|
||||
(get: scenes; set: savescene, modifyscene, scene)
|
||||
new unified syntax for multiple lights
|
||||
in group and scene commands
|
||||
don't query status after set: use bridge response instead
|
||||
added queryAfterSet attribute
|
||||
- feature: HUEDevice: added support for HUE scenes (set: savescene, scene)
|
||||
new unified syntax for multiple lights in lights command
|
||||
- feature: LightScene: support HUE scenes
|
||||
added asyncDelay attribute
|
||||
- bugfix: 10_IT: Fix wrong V3 dimm/off code
|
||||
- feature: 73_km200: Improving error message in state
|
||||
- feature: SYSMON: FormatString for SYSMON_ShowValues.
|
||||
|
@ -39,7 +39,7 @@ sub HUEBridge_Initialize($)
|
||||
$hash->{SetFn} = "HUEBridge_Set";
|
||||
$hash->{GetFn} = "HUEBridge_Get";
|
||||
$hash->{UndefFn} = "HUEBridge_Undefine";
|
||||
$hash->{AttrList}= "key disable:1 httpUtils:1,0 pollDevices:1";
|
||||
$hash->{AttrList}= "key disable:1 httpUtils:1,0 pollDevices:1 queryAfterSet:1";
|
||||
}
|
||||
|
||||
sub
|
||||
@ -226,14 +226,39 @@ sub HUEBridge_Pair($)
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
HUEBridge_string2array($)
|
||||
{
|
||||
my ($lights) = @_;
|
||||
|
||||
my %lights = ();
|
||||
foreach my $part ( split(',', $lights) ) {
|
||||
my $light = $part;
|
||||
$light = $defs{$light}{ID} if( defined $defs{$light} && $defs{$light}{TYPE} eq 'HUEDevice' );
|
||||
if( $light =~ m/^G/ ) {
|
||||
my $lights = $defs{$part}->{lights};
|
||||
foreach my $light ( split(',', $lights) ) {
|
||||
$lights{$light} = 1;
|
||||
}
|
||||
} else {
|
||||
$lights{$light} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my @lights = sort {$a<=>$b} keys(%lights);
|
||||
return \@lights;
|
||||
}
|
||||
|
||||
sub
|
||||
HUEBridge_Set($@)
|
||||
{
|
||||
my ($hash, $name, $cmd, $arg, @params) = @_;
|
||||
my ($hash, $name, $cmd, @args) = @_;
|
||||
my ($arg, @params) = @args;
|
||||
|
||||
# usage check
|
||||
if($cmd eq 'statusRequest') {
|
||||
return "usage: statusRequest" if( @args != 0 );
|
||||
|
||||
$hash->{LOCAL} = 1;
|
||||
#RemoveInternalTimer($hash);
|
||||
HUEBridge_GetUpdate($hash);
|
||||
@ -241,6 +266,8 @@ HUEBridge_Set($@)
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'swupdate') {
|
||||
return "usage: swupdate" if( @args != 0 );
|
||||
|
||||
my $obj = {
|
||||
'swupdate' => { 'updatestate' => 3, },
|
||||
};
|
||||
@ -256,9 +283,13 @@ HUEBridge_Set($@)
|
||||
return "starting update";
|
||||
|
||||
} elsif($cmd eq 'autocreate') {
|
||||
return "usage: autocreate" if( @args != 0 );
|
||||
|
||||
return HUEBridge_Autocreate($hash,1);
|
||||
|
||||
} elsif($cmd eq 'autodetect') {
|
||||
return "usage: autodetect" if( @args != 0 );
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, 'lights', undef, 'POST');
|
||||
|
||||
return $result->{success}{'/lights'} if( $result->{success} );
|
||||
@ -267,10 +298,14 @@ HUEBridge_Set($@)
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'delete') {
|
||||
return "usage: delete <id>" if( @args != 1 );
|
||||
|
||||
if( defined $defs{$arg} && $defs{$arg}{TYPE} eq 'HUEDevice' ) {
|
||||
$arg = $defs{$arg}{ID};
|
||||
}
|
||||
|
||||
return "$arg is not hue light number" if( $arg !~ m/^\d+$/ );
|
||||
|
||||
my $code = $name ."-". $arg;
|
||||
if( defined($modules{HUEDevice}{defptr}{$code}) ) {
|
||||
CommandDelete( undef, "$modules{HUEDevice}{defptr}{$code}{NAME}" );
|
||||
@ -283,15 +318,10 @@ HUEBridge_Set($@)
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'creategroup') {
|
||||
return "usage: creategroup <name> <lights>" if( @args < 2 );
|
||||
|
||||
my @lights = ();
|
||||
for my $param (@params) {
|
||||
$param = $defs{$param}{ID} if( defined $defs{$param} && $defs{$param}{TYPE} eq 'HUEDevice' );
|
||||
push( @lights, $param );
|
||||
}
|
||||
|
||||
my $obj = { 'name' => $arg,
|
||||
'lights' => \@lights,
|
||||
my $obj = { 'name' => join( ' ', @args[0..@args-2]),
|
||||
'lights' => HUEBridge_string2array($args[@args-1]),
|
||||
};
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, 'groups', $obj, 'POST');
|
||||
@ -307,7 +337,10 @@ HUEBridge_Set($@)
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'deletegroup') {
|
||||
return "usage: deletegroup <id>" if( @args != 1 );
|
||||
|
||||
if( defined $defs{$arg} && $defs{$arg}{TYPE} eq 'HUEDevice' ) {
|
||||
return "$arg is not a hue group" if( $defs{$arg}{ID} != m/^G/ );
|
||||
$defs{$arg}{ID} =~ m/G(.*)/;
|
||||
$arg = $1;
|
||||
}
|
||||
@ -318,12 +351,66 @@ HUEBridge_Set($@)
|
||||
CommandSave(undef,undef) if( AttrVal( "autocreate", "autosave", 1 ) );
|
||||
}
|
||||
|
||||
return "$arg is not hue group number" if( $arg !~ m/^\d+$/ );
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, "groups/$arg", undef, 'DELETE');
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'savescene') {
|
||||
return "usage: savescene <id> <name> <lights>" if( @args < 3 );
|
||||
|
||||
my $obj = { 'name' => join( ' ', @args[1..@args-2]),
|
||||
'lights' => HUEBridge_string2array($args[@args-1]),
|
||||
};
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, "scenes/$arg", $obj, 'PUT');
|
||||
|
||||
if( $result->{success} ) {
|
||||
return "created $arg";
|
||||
}
|
||||
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'modifyscene') {
|
||||
return "usage: modifyscene <id> <light> <light args>" if( @args < 3 );
|
||||
|
||||
my( $light, @aa ) = @params;
|
||||
$light = $defs{$light}{ID} if( defined $defs{$light} && $defs{$light}{TYPE} eq 'HUEDevice' );
|
||||
|
||||
my %obj;
|
||||
if( (my $joined = join(" ", @aa)) =~ /:/ ) {
|
||||
my @cmds = split(":", $joined);
|
||||
for( my $i = 0; $i <= $#cmds; ++$i ) {
|
||||
HUEDevice_SetParam(undef, \%obj, split(" ", $cmds[$i]) );
|
||||
}
|
||||
} else {
|
||||
my ($cmd, $value, $value2, @a) = @aa;
|
||||
|
||||
HUEDevice_SetParam(undef, \%obj, $cmd, $value, $value2);
|
||||
}
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, "scenes/$arg/lights/$light/state", \%obj, 'PUT');
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'scene') {
|
||||
return "usage: scene <id>" if( @args != 1 );
|
||||
|
||||
my $obj = { 'scene' => $arg };
|
||||
my $result = HUEBridge_Call($hash, undef, "groups/0/action", $obj, 'PUT');
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
InternalTimer(gettimeofday()+10, "HUEBridge_GetUpdate", $hash, 0);
|
||||
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'deletewhitelist') {
|
||||
return "usage: deletewhitelist <key>" if( @args != 1 );
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, "config/whitelist/$arg", undef, 'DELETE');
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
@ -331,6 +418,8 @@ HUEBridge_Set($@)
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'touchlink') {
|
||||
return "usage: touchlink" if( @args != 0 );
|
||||
|
||||
my $obj = { 'touchlink' => JSON::true };
|
||||
|
||||
my $result = HUEBridge_Call($hash, undef, 'config', $obj, 'PUT');
|
||||
@ -342,7 +431,7 @@ HUEBridge_Set($@)
|
||||
|
||||
|
||||
} else {
|
||||
my $list = "delete creategroup deletegroup deletewhitlist touchlink autocreate:noArg statusRequest:noArg";
|
||||
my $list = "delete creategroup deletegroup savescene modifyscene scene deletewhitlist touchlink autocreate:noArg statusRequest:noArg";
|
||||
$list .= " swupdate:noArg" if( defined($hash->{updatestate}) && $hash->{updatestate} =~ '^2' );
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
@ -356,10 +445,11 @@ HUEBridge_Get($@)
|
||||
return "$name: get needs at least one parameter" if( !defined($cmd) );
|
||||
|
||||
# usage check
|
||||
if($cmd eq 'devices') {
|
||||
if($cmd eq 'devices'
|
||||
|| $cmd eq 'lights') {
|
||||
my $result = HUEBridge_Call($hash, undef, 'lights', undef);
|
||||
my $ret = "";
|
||||
foreach my $key ( sort {$a<=>$b} keys %$result ) {
|
||||
foreach my $key ( sort {$a<=>$b} keys %{$result} ) {
|
||||
my $code = $name ."-". $key;
|
||||
my $fhem_name ="";
|
||||
$fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) );
|
||||
@ -372,7 +462,7 @@ HUEBridge_Get($@)
|
||||
my $result = HUEBridge_Call($hash, undef, 'groups', undef);
|
||||
$result->{0} = { name => 'Lightset 0', type => 'LightGroup', lights => ["ALL"] };
|
||||
my $ret = "";
|
||||
foreach my $key ( sort {$a<=>$b} keys %$result ) {
|
||||
foreach my $key ( sort {$a<=>$b} keys %{$result} ) {
|
||||
my $code = $name ."-G". $key;
|
||||
my $fhem_name ="";
|
||||
$fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) );
|
||||
@ -381,16 +471,25 @@ HUEBridge_Get($@)
|
||||
$ret = sprintf( "%2s %-15s %-15s %-15s %s\n", "ID", "NAME", "FHEM", "TYPE", "LIGHTS" ) .$ret if( $ret );
|
||||
return $ret;
|
||||
|
||||
} elsif($cmd eq 'scenes') {
|
||||
my $result = HUEBridge_Call($hash, undef, 'scenes', undef);
|
||||
my $ret = "";
|
||||
foreach my $key ( sort {$a cmp $b} keys %{$result} ) {
|
||||
$ret .= sprintf( "%-20s %-20s %s\n", $key, $result->{$key}{name}, join( ",", @{$result->{$key}{lights}} ) );
|
||||
}
|
||||
$ret = sprintf( "%-20s %-20s %s\n", "ID", "NAME", "LIGHTS" ) .$ret if( $ret );
|
||||
return $ret;
|
||||
|
||||
} elsif($cmd eq 'sensors') {
|
||||
my $result = HUEBridge_Call($hash, undef, 'sensors', undef);
|
||||
my $ret = "";
|
||||
foreach my $key ( sort {$a<=>$b} keys %$result ) {
|
||||
foreach my $key ( sort {$a<=>$b} keys %{$result} ) {
|
||||
my $code = $name ."-S". $key;
|
||||
my $fhem_name ="";
|
||||
$fhem_name = $modules{HUEDevice}{defptr}{$code}->{NAME} if( defined($modules{HUEDevice}{defptr}{$code}) );
|
||||
$ret .= sprintf( "%2i: %-15s %-15s %-15s\n", $key, $result->{$key}{name}, $fhem_name, $result->{$key}{type} );
|
||||
}
|
||||
$ret = sprintf( "%2s %-15s %-15s %-15s %s\n", "ID", "NAME", "FHEM", "TYPE", "LIGHTS" ) .$ret if( $ret );
|
||||
$ret = sprintf( "%2s %-15s %-15s %-15s\n", "ID", "NAME", "FHEM", "TYPE" ) .$ret if( $ret );
|
||||
return $ret;
|
||||
|
||||
} elsif($cmd eq 'whitelist') {
|
||||
@ -404,7 +503,7 @@ HUEBridge_Get($@)
|
||||
return $ret;
|
||||
|
||||
} else {
|
||||
return "Unknown argument $cmd, choose one of devices:noArg groups:noArg sensors:noArg whitelist:noArg";
|
||||
return "Unknown argument $cmd, choose one of devices:noArg groups:noArg scenes:noArg sensors:noArg whitelist:noArg";
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,7 +601,7 @@ HUEBridge_Autocreate($;$)
|
||||
|
||||
my $autocreated = 0;
|
||||
my $result = HUEBridge_Call($hash,undef, 'lights', undef);
|
||||
foreach my $key ( keys %$result ) {
|
||||
foreach my $key ( keys %{$result} ) {
|
||||
my $id= $key;
|
||||
|
||||
my $code = $name ."-". $id;
|
||||
@ -531,7 +630,7 @@ HUEBridge_Autocreate($;$)
|
||||
|
||||
$result = HUEBridge_Call($hash,undef, 'groups', undef);
|
||||
$result->{0} = { name => "Lightset 0", };
|
||||
foreach my $key ( keys %$result ) {
|
||||
foreach my $key ( keys %{$result} ) {
|
||||
my $id= $key;
|
||||
|
||||
my $code = $name ."-G". $id;
|
||||
@ -580,23 +679,38 @@ sub HUEBridge_ProcessResponse($$)
|
||||
$hash->{STATE} = $error;
|
||||
}
|
||||
|
||||
if( 0 ) {
|
||||
if( !AttrVal( $name,'queryAfterSet', 0 ) ) {
|
||||
my $successes;
|
||||
my $errors;
|
||||
my %json = ();
|
||||
foreach my $item (@{$obj}) {
|
||||
if( my $success = $item->{success} ) {
|
||||
next if( ref($success) ne 'HASH' );
|
||||
foreach my $key ( keys %{$success} ) {
|
||||
my @l = split( '/', $key );
|
||||
next if( !$l[1] );
|
||||
if( $l[1] eq 'lights' && $l[3] eq 'state' ) {
|
||||
$json{$l[2]}->{state}->{$l[4]} = $success->{$key};
|
||||
$successes++;
|
||||
|
||||
} elsif( $l[1] eq 'groups' && $l[3] eq 'action' ) {
|
||||
my $code = $name ."-G". $l[2];
|
||||
my $d = $modules{HUEDevice}{defptr}{$code};
|
||||
my $lights = $d->{lights};
|
||||
foreach my $light ( split(',', $lights) ) {
|
||||
$json{$light}->{state}->{$l[4]} = $success->{$key};
|
||||
$successes++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} elsif( my $error = $item->{error} ) {
|
||||
my $msg = $error->{'description'};
|
||||
Log3 $name, 3, $msg;
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
#Log 3, Dumper \%json;
|
||||
|
||||
foreach my $id ( keys %json ) {
|
||||
my $code = $name ."-". $id;
|
||||
@ -605,7 +719,9 @@ if( 0 ) {
|
||||
HUEDevice_Parse( $chash, $json{$id} );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#return undef if( !$errors && $successes );
|
||||
|
||||
return ($obj->[0]);
|
||||
}
|
||||
@ -698,7 +814,8 @@ HUEBridge_HTTP_Call($$$;$)
|
||||
} elsif($ret eq '') {
|
||||
return undef;
|
||||
} elsif($ret =~ /^error:(\d){3}$/) {
|
||||
return "HTTP Error Code " . $1;
|
||||
my %result = { error => "HTTP Error Code $1" };
|
||||
return \%result;
|
||||
}
|
||||
|
||||
if( !$ret ) {
|
||||
@ -807,11 +924,15 @@ HUEBridge_dispatch($$$;$)
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $queryAfterSet = AttrVal( $name,'queryAfterSet', 0 );
|
||||
|
||||
$json = from_json($data) if( !$json );
|
||||
my $type = $param->{type};
|
||||
|
||||
if( ref($json) eq 'ARRAY' )
|
||||
{
|
||||
HUEBridge_ProcessResponse($hash,$json) if( !$queryAfterSet );
|
||||
|
||||
if( defined($json->[0]->{error}))
|
||||
{
|
||||
my $error = $json->[0]->{error}->{'description'};
|
||||
@ -892,13 +1013,15 @@ HUEBridge_dispatch($$$;$)
|
||||
HUEDevice_Parse($param->{chash},$json);
|
||||
|
||||
} elsif( $type =~ m/^lights\/(\d*)\/state$/ ) {
|
||||
my $chash = $param->{chash};
|
||||
if( $chash->{helper}->{update_timeout} ) {
|
||||
RemoveInternalTimer($chash);
|
||||
InternalTimer(gettimeofday()+1, "HUEDevice_GetUpdate", $chash, 0);
|
||||
} else {
|
||||
RemoveInternalTimer($chash);
|
||||
HUEDevice_GetUpdate( $chash );
|
||||
if( $queryAfterSet ) {
|
||||
my $chash = $param->{chash};
|
||||
if( $chash->{helper}->{update_timeout} ) {
|
||||
RemoveInternalTimer($chash);
|
||||
InternalTimer(gettimeofday()+1, "HUEDevice_GetUpdate", $chash, 0);
|
||||
} else {
|
||||
RemoveInternalTimer($chash);
|
||||
HUEDevice_GetUpdate( $chash );
|
||||
}
|
||||
}
|
||||
|
||||
} elsif( $type =~ m/^groups\/(\d*)\/action$/ ) {
|
||||
@ -1000,7 +1123,8 @@ HUEBridge_HTTP_Request($$$@)
|
||||
}
|
||||
undef $conn;
|
||||
if($header[0] =~ /^[^ ]+ ([\d]{3})/ && $1 != 200) {
|
||||
return "error:" . $1;
|
||||
my %result = { error => "error: $1" };
|
||||
return \%result;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
@ -1057,6 +1181,8 @@ HUEBridge_HTTP_Request($$$@)
|
||||
list the devices known to the bridge.</li>
|
||||
<li>groups<br>
|
||||
list the groups known to the bridge.</li>
|
||||
<li>scenes<br>
|
||||
list the scenes known to the bridge.</li>
|
||||
<li>sensors<br>
|
||||
list the sensors known to the bridge.</li>
|
||||
<li>whitelist<br>
|
||||
@ -1074,11 +1200,18 @@ HUEBridge_HTTP_Request($$$@)
|
||||
can be created by <code>set <bridge> autocreate</code>.</li>
|
||||
<li>delete <name>|<id><br>
|
||||
Deletes the given device in the bridge and deletes the associated fhem device.</li>
|
||||
<li>creategroup <name> <light-1>[ <light-2>..<lignt-n>]<br>
|
||||
Create a group out of <light-1>-<light-n> in the bridge.
|
||||
The lights can be given as fhem device names or bridge device numbers.</li>
|
||||
<li>creategroup <name> <lights><br>
|
||||
Create a group out of <lights> in the bridge.
|
||||
The lights are given as a comma sparated list of fhem device names or bridge light numbers.</li>
|
||||
<li>deletegroup <name>|<id><br>
|
||||
Deletes the given group in the bridge and deletes the associated fhem device.</li>
|
||||
<li>savescene <id> <name> <lights><br>
|
||||
Create a scene from the current state of <lights> in the bridge.
|
||||
The lights are given as a comma sparated list of fhem device names or bridge light numbers.</li>
|
||||
<li>scene <id><br>
|
||||
Recalls the scene with the given id.</li>
|
||||
<li>modifyscene <id> <light> <light-args><br>
|
||||
Modifys the given scene in the bridge.</li>
|
||||
<li>deletwhitelist <key><br>
|
||||
Deletes the given key from the whitelist in the bridge.</li>
|
||||
<li>touchlink<br>
|
||||
|
@ -16,6 +16,9 @@ use POSIX;
|
||||
use JSON;
|
||||
use SetExtensions;
|
||||
|
||||
#require "30_HUEBridge.pm";
|
||||
#require "$attr{global}{modpath}/FHEM/30_HUEBridge.pm";
|
||||
|
||||
use vars qw(%FW_webArgs); # all arguments specified in the GET
|
||||
|
||||
my %hueModels = (
|
||||
@ -270,7 +273,7 @@ HUEDevice_SetParam($$@)
|
||||
if( $cmd eq "color" ) {
|
||||
$value = int(1000000/$value);
|
||||
$cmd = 'ct';
|
||||
} elsif( $cmd eq "toggle" ) {
|
||||
} elsif( $name && $cmd eq "toggle" ) {
|
||||
$cmd = ReadingsVal($name,"state","on") eq "off" ? "on" :"off";
|
||||
} elsif( $cmd =~ m/^dim(\d+)/ ) {
|
||||
$value2 = $value;
|
||||
@ -290,7 +293,7 @@ HUEDevice_SetParam($$@)
|
||||
|
||||
if($cmd eq 'on') {
|
||||
$obj->{'on'} = JSON::true;
|
||||
$obj->{'bri'} = 254 if( ReadingsVal($name,"bri","0") eq 0 );
|
||||
$obj->{'bri'} = 254 if( $name && ReadingsVal($name,"bri","0") eq 0 );
|
||||
$obj->{'transitiontime'} = $value * 10 if( defined($value) );
|
||||
|
||||
} elsif($cmd eq 'off') {
|
||||
@ -318,13 +321,13 @@ HUEDevice_SetParam($$@)
|
||||
$obj->{'bri'} = 0+$value;
|
||||
$obj->{'transitiontime'} = $value2 * 10 if( defined($value2) );
|
||||
|
||||
} elsif($cmd eq "dimUp") {
|
||||
} elsif($name && $cmd eq "dimUp") {
|
||||
if( $defs{$name}->{IODev}->{helper}{apiversion} && $defs{$name}->{IODev}->{helper}{apiversion} >= (1<<16) + (7<<8) ) {
|
||||
$obj->{'on'} = JSON::true if( !$defs{$name}->{helper}{on} );
|
||||
$obj->{'bri_inc'} = 25;
|
||||
$obj->{'bri_inc'} = $value if( defined($value) );
|
||||
$obj->{'transitiontime'} = 1;
|
||||
$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
#$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
} else {
|
||||
my $bri = ReadingsVal($name,"bri","0");
|
||||
$bri += 25;
|
||||
@ -336,13 +339,13 @@ HUEDevice_SetParam($$@)
|
||||
$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
}
|
||||
|
||||
} elsif($cmd eq "dimDown") {
|
||||
} elsif($name && $cmd eq "dimDown") {
|
||||
if( $defs{$name}->{IODev}->{helper}{apiversion} && $defs{$name}->{IODev}->{helper}{apiversion} >= (1<<16) + (7<<8) ) {
|
||||
$obj->{'on'} = JSON::true if( !$defs{$name}->{helper}{on} );
|
||||
$obj->{'bri_inc'} = -25;
|
||||
$obj->{'bri_inc'} = -$value if( defined($value) );
|
||||
$obj->{'transitiontime'} = 1;
|
||||
$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
#$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
} else {
|
||||
my $bri = ReadingsVal($name,"bri","0");
|
||||
$bri -= 25;
|
||||
@ -375,7 +378,7 @@ HUEDevice_SetParam($$@)
|
||||
} elsif( $cmd eq "rgb" && $value =~ m/^(..)(..)(..)/) {
|
||||
my( $r, $g, $b ) = (hex($1)/255.0, hex($2)/255.0, hex($3)/255.0);
|
||||
|
||||
if( !defined( AttrVal($name, "model", undef) ) ) {
|
||||
if( $name && !defined( AttrVal($name, "model", undef) ) ) {
|
||||
my( $h, $s, $v ) = Color::rgb2hsv($r,$g,$b);
|
||||
|
||||
$obj->{'on'} = JSON::true;
|
||||
@ -426,11 +429,11 @@ HUEDevice_SetParam($$@)
|
||||
$obj->{'effect'} = $value;
|
||||
} elsif( $cmd eq "transitiontime" ) {
|
||||
$obj->{'transitiontime'} = 0+$value;
|
||||
} elsif( $cmd eq "delayedUpdate" ) {
|
||||
} elsif( $name && $cmd eq "delayedUpdate" ) {
|
||||
$defs{$name}->{helper}->{update_timeout} = 1;
|
||||
} elsif( $cmd eq "immediateUpdate" ) {
|
||||
} elsif( $name && $cmd eq "immediateUpdate" ) {
|
||||
$defs{$name}->{helper}->{update_timeout} = 0;
|
||||
} elsif( $cmd eq "noUpdate" ) {
|
||||
} elsif( $name && $cmd eq "noUpdate" ) {
|
||||
$defs{$name}->{helper}->{update_timeout} = -1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -443,20 +446,17 @@ sub
|
||||
HUEDevice_Set($@)
|
||||
{
|
||||
my ($hash, $name, @aa) = @_;
|
||||
my ($cmd, @args) = @aa;
|
||||
|
||||
my %obj;
|
||||
|
||||
$hash->{helper}->{update_timeout} = AttrVal($name, "delayedUpdate", 0);
|
||||
$hash->{helper}->{update_timeout} = AttrVal($name, "delayedUpdate", 1);
|
||||
|
||||
if( $hash->{helper}->{devtype} eq 'G' ) {
|
||||
if( $aa[0] eq 'lights' ) {
|
||||
my @lights = ();
|
||||
for my $param (@aa[1..@aa-1]) {
|
||||
$param = $defs{$param}{ID} if( defined $defs{$param} && $defs{$param}{TYPE} eq 'HUEDevice' );
|
||||
push( @lights, $param );
|
||||
}
|
||||
if( $cmd eq 'lights' ) {
|
||||
return "usage: lights <lights>" if( @args != 1 );
|
||||
|
||||
my $obj = { 'lights' => \@lights, };
|
||||
my $obj = { 'lights' => HUEBridge_string2array($args[0]), };
|
||||
|
||||
my $result = HUEDevice_ReadFromServer($hash,$hash->{ID},$obj);
|
||||
if( $result->{success} ) {
|
||||
@ -465,20 +465,51 @@ HUEDevice_Set($@)
|
||||
}
|
||||
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
return undef;
|
||||
|
||||
} elsif( $cmd eq 'savescene' ) {
|
||||
return "usage: savescene <id>" if( @args != 1 );
|
||||
|
||||
return fhem( "set $hash->{IODev}{NAME} savescene $aa[1] $aa[1] $hash->{NAME}" );
|
||||
|
||||
} elsif( $cmd eq 'scene' ) {
|
||||
return "usage: scene <id>" if( @args != 1 );
|
||||
|
||||
my $obj = { 'scene' => $aa[1] };
|
||||
$hash->{helper}->{update} = 1;
|
||||
my $result = HUEDevice_ReadFromServer($hash,"$hash->{ID}/action",$obj);
|
||||
return $result->{error}{description} if( $result->{error} );
|
||||
|
||||
if( defined($result) && $result->{'error'} ) {
|
||||
$hash->{STATE} = $result->{'error'}->{'description'};
|
||||
return undef;
|
||||
}
|
||||
|
||||
return undef if( !defined($result) );
|
||||
|
||||
if( $hash->{helper}->{update_timeout} == -1 ) {
|
||||
} elsif( $hash->{helper}->{update_timeout} ) {
|
||||
RemoveInternalTimer($hash);
|
||||
InternalTimer(gettimeofday()+$hash->{helper}->{update_timeout}, "HUEDevice_GetUpdate", $hash, 0);
|
||||
} else {
|
||||
RemoveInternalTimer($hash);
|
||||
HUEDevice_GetUpdate( $hash );
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
} elsif( $hash->{helper}->{devtype} eq 'S' ) {
|
||||
|
||||
if( $aa[0] eq "statusRequest" ) {
|
||||
if( $cmd eq "statusRequest" ) {
|
||||
RemoveInternalTimer($hash);
|
||||
HUEDevice_GetUpdate($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
return "Unknown argument $aa[0], choose one of statusRequest:noArg";
|
||||
return "Unknown argument $cmd, choose one of statusRequest:noArg";
|
||||
}
|
||||
|
||||
if( $aa[0] eq 'rename' ) {
|
||||
if( $cmd eq 'rename' ) {
|
||||
my $new_name = join( ' ', @aa[1..@aa-1]);
|
||||
my $obj = { 'name' => $new_name, };
|
||||
|
||||
@ -534,9 +565,9 @@ HUEDevice_Set($@)
|
||||
my $result;
|
||||
if( $hash->{helper}->{devtype} eq 'G' ) {
|
||||
$hash->{helper}->{update} = 1;
|
||||
$result = HUEDevice_ReadFromServer($hash,$hash->{ID}."/action",\%obj);
|
||||
$result = HUEDevice_ReadFromServer($hash,"$hash->{ID}/action",\%obj);
|
||||
} else {
|
||||
$result = HUEDevice_ReadFromServer($hash,$hash->{ID}."/state",\%obj);
|
||||
$result = HUEDevice_ReadFromServer($hash,"$hash->{ID}/state",\%obj);
|
||||
}
|
||||
|
||||
if( defined($result) && $result->{'error'} ) {
|
||||
@ -544,6 +575,7 @@ HUEDevice_Set($@)
|
||||
return undef;
|
||||
}
|
||||
|
||||
$hash->{".triggerUsed"} = 1;
|
||||
return undef if( !defined($result) );
|
||||
|
||||
if( $hash->{helper}->{update_timeout} == -1 ) {
|
||||
@ -571,6 +603,7 @@ HUEDevice_Set($@)
|
||||
#$list .= " dim06% dim12% dim18% dim25% dim31% dim37% dim43% dim50% dim56% dim62% dim68% dim75% dim81% dim87% dim93% dim100%" if( $subtype =~ m/dimmer/ );
|
||||
|
||||
$list .= " lights" if( $hash->{helper}->{devtype} eq 'G' );
|
||||
$list .= " savescene scene" if( $hash->{helper}->{devtype} eq 'G' );
|
||||
$list .= " rename";
|
||||
|
||||
return SetExtensions($hash, $list, $name, @aa);
|
||||
@ -826,19 +859,16 @@ HUEDevice_Parse($$)
|
||||
$hash->{uniqueid} = $result->{'uniqueid'};
|
||||
|
||||
if( $hash->{helper}->{devtype} eq 'G' ) {
|
||||
$hash->{STATE} = 'Initialized';
|
||||
$hash->{lights} = join( ",", @{$result->{lights}} ) if( $result->{lights} );
|
||||
|
||||
foreach my $id ( @{$result->{lights}} ) {
|
||||
my $code = $hash->{IODev}->{NAME} ."-". $id;
|
||||
my $chash = $modules{HUEDevice}{defptr}{$code};
|
||||
|
||||
HUEDevice_GetUpdate($chash) if( defined($chash) && defined($hash->{helper}->{update}) );
|
||||
if( defined($hash->{helper}->{update}) ) {
|
||||
delete $hash->{helper}->{update};
|
||||
fhem( "set $hash->{IODev}{NAME} statusRequest" );
|
||||
return undef;
|
||||
}
|
||||
|
||||
delete $hash->{helper}->{update};
|
||||
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
$hash->{modelid} = $result->{modelid};
|
||||
@ -935,6 +965,7 @@ HUEDevice_Parse($$)
|
||||
my $reachable = $state->{reachable}?1:0;
|
||||
my $colormode = $state->{'colormode'};
|
||||
my $bri = $state->{'bri'};
|
||||
$bri = $hash->{helper}{bri} if( !defined( $bri) );
|
||||
my $ct = $state->{'ct'};
|
||||
my $hue = $state->{'hue'};
|
||||
my $sat = $state->{'sat'};
|
||||
@ -1007,6 +1038,9 @@ HUEDevice_Parse($$)
|
||||
my $rgb = CommandGet("","$name rgb");
|
||||
if( $rgb ne $hash->{helper}{rgb} ) { readingsSingleUpdate($hash,"rgb", $rgb,1); };
|
||||
$hash->{helper}{rgb} = $rgb;
|
||||
|
||||
$hash->{helper}->{update_timeout} = -1;
|
||||
RemoveInternalTimer($hash);
|
||||
}
|
||||
|
||||
1;
|
||||
@ -1107,9 +1141,12 @@ HUEDevice_Parse($$)
|
||||
<li>delayedUpdate</li>
|
||||
<li>immediateUpdate</li>
|
||||
<br>
|
||||
<li>lights <light-1>[ <light-2>..<light-n>]<br>
|
||||
<li>savescene <id></li>
|
||||
<li>scene</li>
|
||||
<br>
|
||||
<li>lights <lights><br>
|
||||
Only valid for groups. Changes the list of lights in this group.
|
||||
The lights can be given as fhem device names or bridge device numbers.</li>
|
||||
The lights are given as a comma sparated list of fhem device names or bridge light numbers.</li>
|
||||
<li>rename <new name><br>
|
||||
Renames the device in the bridge and changes the fhem alias.</li>
|
||||
<br>
|
||||
|
@ -29,7 +29,7 @@ sub LightScene_Initialize($)
|
||||
$hash->{SetFn} = "LightScene_Set";
|
||||
$hash->{GetFn} = "LightScene_Get";
|
||||
$hash->{AttrFn} = "LightScene_Attr";
|
||||
$hash->{AttrList} = "followDevices:1,2 switchingOrder ". $readingFnAttributes;
|
||||
$hash->{AttrList} = "async_delay followDevices:1,2 switchingOrder ". $readingFnAttributes;
|
||||
|
||||
$hash->{FW_detailFn} = "LightScene_detailFn";
|
||||
$data{FWEXT}{"/LightScene"}{FUNC} = "LightScene_CGI"; #mod
|
||||
@ -77,6 +77,9 @@ sub LightScene_Define($$)
|
||||
|
||||
LightScene_updateHelper( $hash, AttrVal($name,"switchingOrder",undef) );
|
||||
|
||||
my @arr = ();
|
||||
$hash->{".asyncQueue"} = \@arr;
|
||||
|
||||
$hash->{STATE} = 'Initialized';
|
||||
|
||||
return undef;
|
||||
@ -410,9 +413,9 @@ LightScene_Load($)
|
||||
}
|
||||
|
||||
sub
|
||||
LightScene_SaveDevice($$)
|
||||
LightScene_SaveDevice($$;$)
|
||||
{
|
||||
my($hash,$d) = @_;
|
||||
my($hash,$d,$scene) = @_;
|
||||
|
||||
my $state = "";
|
||||
my $icon = undef;
|
||||
@ -490,10 +493,22 @@ LightScene_SaveDevice($$)
|
||||
$state = "rgb ". $state if( $state ne "off" );
|
||||
} elsif( $type eq 'HUEDevice' ) {
|
||||
my $subtype = AttrVal($d,"subType","");
|
||||
if( $subtype eq "switch" || Value($d) eq "off" ) {
|
||||
if( $defs{$d}->{helper}->{devtype} eq "G" ) {
|
||||
|
||||
if( $scene ) {
|
||||
my $id = "FHEM-$hash->{NAME}-$scene";
|
||||
$state = "scene $id";
|
||||
fhem( "set $d savescene $id" );
|
||||
} else {
|
||||
$state = "<unknown>";
|
||||
}
|
||||
|
||||
} elsif( $subtype eq "switch" || Value($d) eq "off" ) {
|
||||
$state = Value($d);
|
||||
|
||||
} elsif( $subtype eq "dimmer" ) {
|
||||
$state = "bri ". ReadingsVal($d,'bri',"0");
|
||||
|
||||
} elsif( $subtype =~ m/color|ct/ ) {
|
||||
my $cm = ReadingsVal($d,"colormode","");
|
||||
if( $cm eq "ct" ) {
|
||||
@ -505,6 +520,7 @@ LightScene_SaveDevice($$)
|
||||
$state = "bri ". ReadingsVal($d,'bri',"0") ." : xy ". ReadingsVal($d,'xy',"");
|
||||
}
|
||||
}
|
||||
|
||||
} elsif( $type eq 'IT' ) {
|
||||
my $subtype = AttrVal($d,"model","");
|
||||
if( $subtype eq "itswitch" ) {
|
||||
@ -535,11 +551,22 @@ LightScene_RestoreDevice($$$)
|
||||
return ("",0) if( $state eq $cmd );
|
||||
}
|
||||
|
||||
my $async_delay = AttrVal($hash->{NAME}, "async_delay", undef);
|
||||
my $ret;
|
||||
if( $cmd =~m/^;/ ) {
|
||||
$ret = AnalyzeCommandChain(undef,"$cmd");
|
||||
if(defined($async_delay)) {
|
||||
push @{$hash->{".asyncQueue"}}, $cmd;
|
||||
} else {
|
||||
$ret = AnalyzeCommandChain(undef,$cmd);
|
||||
}
|
||||
|
||||
} else {
|
||||
$ret = CommandSet(undef,"$d $cmd");
|
||||
if(defined($async_delay)) {
|
||||
push @{$hash->{".asyncQueue"}}, "$d $cmd";
|
||||
} else {
|
||||
$ret = CommandSet(undef,"$d $cmd");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ($ret,1);
|
||||
@ -608,6 +635,8 @@ LightScene_Set($@)
|
||||
}
|
||||
|
||||
my $count = 0;
|
||||
my $async_delay = AttrVal($hash->{NAME}, "async_delay", undef);
|
||||
my $asyncQueueLength = @{$hash->{".asyncQueue"}};
|
||||
foreach my $d (@devices) {
|
||||
next if(!$defs{$d});
|
||||
if($defs{$d}{INSET}) {
|
||||
@ -616,7 +645,7 @@ LightScene_Set($@)
|
||||
}
|
||||
|
||||
if( $cmd eq "save" ) {
|
||||
my($state,$icon,$type) = LightScene_SaveDevice($hash,$d);
|
||||
my($state,$icon,$type) = LightScene_SaveDevice($hash,$d,$scene);
|
||||
|
||||
if( $icon || ref($state) eq 'ARRAY' || $type eq "SWAP_0000002200000003" || $type eq "HUEDevice" ) {
|
||||
my %desc;
|
||||
@ -667,11 +696,31 @@ LightScene_Set($@)
|
||||
|
||||
LightScene_updateHelper( $hash, AttrVal($name,"switchingOrder",undef) );
|
||||
|
||||
InternalTimer(gettimeofday()+0, "LightScene_asyncQueue", $hash, 0) if( @{$hash->{".asyncQueue"}} && !$asyncQueueLength );
|
||||
|
||||
return $ret;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
LightScene_asyncQueue(@)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
my $cmd = shift @{$hash->{".asyncQueue"}};
|
||||
if(defined $cmd) {
|
||||
if( $cmd =~m/^;/ ) {
|
||||
AnalyzeCommandChain(undef,$cmd);
|
||||
} else {
|
||||
CommandSet(undef, $cmd);
|
||||
}
|
||||
my $async_delay = AttrVal($hash->{NAME}, "async_delay", 0);
|
||||
InternalTimer(gettimeofday()+$async_delay,"LightScene_asyncQueue",$hash,0) if( @{$hash->{".asyncQueue"}} );
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
LightScene_Get($@)
|
||||
{
|
||||
@ -952,6 +1001,15 @@ LightScene_editTable($) {
|
||||
<a name="LightScene_Attr"></a>
|
||||
<b>Attributes</b>
|
||||
<ul>
|
||||
<a name="async_delay"></a>
|
||||
<li>async_delay<br>
|
||||
If this attribute is defined, unfiltered set commands will not be
|
||||
executed in the clients immediately. Instead, they are added to a queue
|
||||
to be executed later. The set command returns immediately, whereas the
|
||||
clients will be set timer-driven, one at a time. The delay between two
|
||||
timercalls is given by the value of async_delay (in seconds) and may be
|
||||
0 for fastest possible execution.
|
||||
</li>
|
||||
<li>lightSceneParamsToSave<br>
|
||||
this attribute can be set on the devices to be included in a scene. it is set to a comma separated list of readings
|
||||
that will be saved. multiple readings separated by : are collated in to a single set command (this has to be supported
|
||||
|
Loading…
x
Reference in New Issue
Block a user