From fe1f717ecc287302af145962e22e94ad63e47d34 Mon Sep 17 00:00:00 2001 From: justme1968 Date: Mon, 18 Feb 2013 20:17:08 +0000 Subject: [PATCH] added modules 30_HUEDevice and 31_HUEBridge for phillips hue and smartlink devices git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@2762 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- CHANGED | 2 + FHEM/30_HUEBridge.pm | 434 ++++++++++++++++++++++++++++++++++++++++ FHEM/31_HUEDevice.pm | 460 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 896 insertions(+) create mode 100644 FHEM/30_HUEBridge.pm create mode 100644 FHEM/31_HUEDevice.pm diff --git a/CHANGED b/CHANGED index 858cc74b1..a0a990795 100644 --- a/CHANGED +++ b/CHANGED @@ -1,4 +1,6 @@ - SVN + - feature: new Modules 30_HUEDevice and 31_HUEBridge for phillips hue and + smartlink devices (by justme1968) - change: SYSSTAT: allow remote monitoring by ssh - change: SYSSTAT: allow less frequent updates for diskusage - feature: new Module 32_SYSSTAT to monitor system load and disk usage diff --git a/FHEM/30_HUEBridge.pm b/FHEM/30_HUEBridge.pm new file mode 100644 index 000000000..0d368889e --- /dev/null +++ b/FHEM/30_HUEBridge.pm @@ -0,0 +1,434 @@ + +package main; + +use strict; +use warnings; +use POSIX; +use JSON; +use Try::Tiny; +use Data::Dumper; +use MIME::Base64; + +sub HUEBridge_Initialize($) +{ + my ($hash) = @_; + + # Provider + $hash->{ReadFn} = "HUEBridge_Read"; + $hash->{WriteFn} = "HUEBridge_Read"; + $hash->{Clients} = ":HUEDevice:"; + + #Consumer + $hash->{DefFn} = "HUEBridge_Define"; + $hash->{SetFn} = "HUEBridge_Set"; + $hash->{UndefFn} = "HUEBridge_Undefine"; + $hash->{AttrList}= "key loglevel:0,1,2,3,4,5"; +} + +sub +HUEBridge_Read($@) +{ + my ($hash,$name,$id,$obj)= @_; + + return HUEBridge_Call($hash, 'lights/' . $id, $obj); +} + +sub HUEBridge_Define($$) +{ + my ($hash, $def) = @_; + + my @args = split("[ \t]+", $def); + + return "Usage: define HUEBridge [interval]" if(@args < 3); + + my ($name, $type, $host, $interval) = @args; + + $interval= 300 unless defined($interval); + if( $interval < 60 ) { $interval = 60; } + + $hash->{STATE} = 'Initialized'; + + $hash->{Host} = $host; + $hash->{INTERVAL} = $interval; + + $attr{$name}{"key"} = join "",map { unpack "H*", chr(rand(256)) } 1..16 unless defined( AttrVal($name, "key", undef) ); + + #HUEBridge_OpenDev($hash); + InternalTimer(gettimeofday()+10, "HUEBridge_OpenDev", $hash, 0); + + return undef; +} + +sub HUEBridge_Undefine($$) +{ + my ($hash,$arg) = @_; + + RemoveInternalTimer($hash); + return undef; +} + +sub HUEBridge_OpenDev($) +{ + my ($hash) = @_; + + my $result = HUEBridge_Call($hash, 'config', undef); + if( !defined($result) ) { + return undef; + } + + $hash->{name} = $result->{'name'}; + $hash->{swversion} = $result->{'swversion'}; + + if( !defined($result->{'mac'}) ) + { + HUEBridge_Pair($hash); + return; + } + + $hash->{mac} = $result->{'mac'}; + + $hash->{STATE} = 'Connected'; + HUEBridge_GetUpdate($hash); + + HUEBridge_Autocreate($hash); + + return undef; +} +sub HUEBridge_Pair($) +{ + my ($hash) = @_; + + $hash->{STATE} = 'Pairing'; + + my $result = HUEBridge_Register($hash); + if( $result->{'error'} ) + { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+5, "HUEBridge_Pair", $hash, 0); + + return undef; + } + + $hash->{STATE} = 'Paired'; + + HUEBridge_OpenDev($hash); + + return undef; +} + + +sub +HUEBridge_Set($@) +{ + my ($hash, $name, $cmd) = @_; + + # usage check + if($cmd eq 'statusRequest') { + RemoveInternalTimer($hash); + HUEBridge_GetUpdate($hash); + return undef; + } else { + return "Unknown argument $cmd, choose one of statusRequest"; + } +} + +sub +HUEBridge_GetUpdate($) +{ + my ($hash) = @_; + + if(!$hash->{LOCAL}) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "HUEBridge_GetUpdate", $hash, 1); + } + + my $text=''; + + return($text); +} + +sub +HUEBridge_Autocreate($) +{ + my ($hash)= @_; + my $name = $hash->{NAME}; + + foreach my $d (keys %defs) { + next if($defs{$d}{TYPE} ne "autocreate"); + return undef if(AttrVal($defs{$d}{NAME},"disable",undef)); + } + + my $result = HUEBridge_Call($hash, 'lights', undef); + + my @defined = (); + foreach my $d (keys %defs) { + next if($defs{$d}{TYPE} ne "HUEDevice"); + if(defined($defs{$d}{fhem}) && defined($defs{$d}{fhem}{id})) { + push(@defined,$defs{$d}{fhem}{id}); + } + } + + foreach my $key ( keys %$result ) + { + my $id= $key; + + my $found = 0; + foreach my $d (keys %defs) { + next if($defs{$d}{TYPE} ne "HUEDevice"); + if(defined($defs{$d}{fhem}) && + defined($defs{$d}{fhem}{id}) && $defs{$d}{fhem}{id} eq $id) { + Log 5, "$name id '$id' already defined as '$defs{$d}{NAME}'"; + $found = 1; + last; + } + } + + if( !$found ) { + my $devname= "HUEDevice" . $id; + my $define= "$devname HUEDevice $id"; + + Log 5, "$name create new device '$devname' for address '$id'"; + + my $cmdret= CommandDefine(undef,$define); + if($cmdret) { + Log 1, "$name: Autocreate: An error occurred while creating device for id '$id': $cmdret"; + } else { + $cmdret= CommandAttr(undef,"$devname alias ".$result->{$id}{name}); + $cmdret= CommandAttr(undef,"$devname room HUEDevice"); + } + } + } + + return undef; +} + +sub HUEBridge_ProcessResponse($$) +{ + my ($hash,$obj) = @_; + + #Log 3, ref($obj); + #Log 3, "Receiving: " . Dumper $obj; + + if( ref($obj) eq 'ARRAY' ) + { + if( defined($obj->[0]->{error})) + { + my $error = $obj->[0]->{error}->{'description'}; + + $hash->{STATE} = $error; + + Log 3, $error; + } + + return ($obj->[0]); + } + elsif( ref($obj) eq 'HASH' ) + { + return $obj; + } + + return undef; +} + +sub HUEBridge_Register($) +{ + my ($hash) = @_; + + my $obj = { + 'username' => AttrVal($hash->{NAME}, "key", ""), + 'devicetype' => 'fhem', + }; + + return HUEBridge_Call($hash, undef, $obj); +} + +#Executes a JSON RPC +sub +HUEBridge_Call($$$) +{ + my ($hash,$path,$obj) = @_; + + #Log 3, "Sending: " . Dumper $obj; + + my $json = undef; + $json = encode_json($obj) if $obj; + + return HUEBridge_HTTP_Call($hash,$path,$json); +} + +#JSON RPC over HTTP +sub HUEBridge_HTTP_Call($$$) +{ + my ($hash,$path,$obj) = @_; + my $uri = "http://" . $hash->{Host} . "/api"; + my $method = 'GET'; + if( defined($obj) ) { + $method = 'PUT'; + + if( $hash->{STATE} eq 'Pairing' ) { + $method = 'POST'; + } else { + $uri .= "/" . AttrVal($hash->{NAME}, "key", ""); + } + } else { + $uri .= "/" . AttrVal($hash->{NAME}, "key", ""); + } + if( defined $path) { + $uri .= "/" . $path; + } + #Log 3, "Url: " . $uri; + my $ret = HUEBridge_HTTP_Request(0,$uri,$method,undef,$obj,undef); + #Log 3, Dumper $ret; + if( !defined($ret) ) { + return undef; + } elsif($ret eq '') { + return undef; + } elsif($ret =~ /^error:(\d){3}$/) { + return "HTTP Error Code " . $1; + } + +# try { +# decode_json($ret); +# } catch { +# return undef; +# } + + return HUEBridge_ProcessResponse($hash,decode_json($ret)); +} + +#adapted version of the CustomGetFileFromURL subroutine from HttpUtils.pm +sub +HUEBridge_HTTP_Request($$$@) +{ + my ($quiet, $url, $method, $timeout, $data, $noshutdown) = @_; + $timeout = 4.0 if(!defined($timeout)); + + my $displayurl= $quiet ? "" : $url; + if($url !~ /^(http|https):\/\/([^:\/]+)(:\d+)?(\/.*)$/) { + Log 1, "HUEBridge_HTTP_Request $displayurl: malformed or unsupported URL"; + return undef; + } + + my ($protocol,$host,$port,$path)= ($1,$2,$3,$4); + + if(defined($port)) { + $port =~ s/^://; + } else { + $port = ($protocol eq "https" ? 443: 80); + } + $path= '/' unless defined($path); + + + my $conn; + if($protocol eq "https") { + eval "use IO::Socket::SSL"; + if($@) { + Log 1, $@; + } else { + $conn = IO::Socket::SSL->new(PeerAddr=>"$host:$port", Timeout=>$timeout); + } + } else { + $conn = IO::Socket::INET->new(PeerAddr=>"$host:$port", Timeout=>$timeout); + } + if(!$conn) { + Log 1, "HUEBridge_HTTP_Request $displayurl: Can't connect to $protocol://$host:$port\n"; + undef $conn; + return undef; + } + + $host =~ s/:.*//; + #my $hdr = ($data ? "POST" : "GET")." $path HTTP/1.0\r\nHost: $host\r\n"; + my $hdr = $method." $path HTTP/1.0\r\nHost: $host\r\n"; + if(defined($data)) { + $hdr .= "Content-Length: ".length($data)."\r\n"; + $hdr .= "Content-Type: application/json"; + } + $hdr .= "\r\n\r\n"; + syswrite $conn, $hdr; + syswrite $conn, $data if(defined($data)); + shutdown $conn, 1 if(!$noshutdown); + + my ($buf, $ret) = ("", ""); + $conn->timeout($timeout); + for(;;) { + my ($rout, $rin) = ('', ''); + vec($rin, $conn->fileno(), 1) = 1; + my $nfound = select($rout=$rin, undef, undef, $timeout); + if($nfound <= 0) { + Log 1, "HUEBridge_HTTP_Request $displayurl: Select timeout/error: $!"; + undef $conn; + return undef; + } + + my $len = sysread($conn,$buf,65536); + last if(!defined($len) || $len <= 0); + $ret .= $buf; + } + + $ret=~ s/(.*?)\r\n\r\n//s; # Not greedy: switch off the header. + my @header= split("\r\n", $1); + my $hostpath= $quiet ? "" : $host . $path; + Log 4, "HUEBridge_HTTP_Request $displayurl: Got data, length: ".length($ret); + if(!length($ret)) { + Log 4, "HUEBridge_HTTP_Request $displayurl: Zero length data, header follows..."; + for (@header) { + Log 4, "HUEBridge_HTTP_Request $displayurl: $_"; + } + } + undef $conn; + if($header[0] =~ /^[^ ]+ ([\d]{3})/ && $1 != 200) { + return "error:" . $1; + } + return $ret; +} + +1; + +=pod +=begin html + + +

HUEBridge

+
    + Module to access the bridge of the phillips hue lighting system.

    + + The actual hue bulbs, living colors or living whites devices are defined as HUEDevice devices. + +

    + All newly found devices are autocreated at startup and added to the room HUEDevice. + +

    + Notes: +
      +
    • This module needs JSON.
      + Pleease install with 'cpan install JSON' or your method of choice.
    • +
    + + +

    + + Define +
      + define <name> HUEBridge <host> [<interval>]
      +
      + + Defines a HUEBridge device with address <host>.

      + + The bridge status will be updated every <interval> seconds. The default and minimum is 60.

      + + Examples: +
        + define bridge HUEBridge 10.0.1.1
        +
      +

    + + + Set +
      +
    • statusRequest
      + Update bridge status.
    • +

    +

+ +=end html +=cut diff --git a/FHEM/31_HUEDevice.pm b/FHEM/31_HUEDevice.pm new file mode 100644 index 000000000..182240c2f --- /dev/null +++ b/FHEM/31_HUEDevice.pm @@ -0,0 +1,460 @@ + +package main; + +use strict; +use warnings; +use POSIX; +use JSON; +use SetExtensions; + +#Hue XY to RGB +#Z = 1 - X - Y +# +#|R| | X | | 3.2333 -1.5262 0.2791 | +#|G| = | Y | * |-0.8268 2.4667 0.3323 | +#|B| | Z | | 0.1294 0.1983 2.0280 | +# +#Example: +#XY == [0.4912, 0.4058] +#Z == 1 - 0.4912 - 0.4058 == 0.103 +# +#R/255 = (0.4912 * 3.2333) + (0.4058 * -1.5262) + (0.103 * 0.2791) = 0.9976 +#G/255 = (0.4912 * -0.8268) + (0.4058 * 2.4667) + (0.103 * 0.3323) = 0.6291 +#B/255 = (0.4912 * 0.1294) + (0.4058 * 0.1983) + (0.103 * 2.0280) = 0.3529 + +my %models = ( + LCT001 => 'HUE Bulb', + LLC001 => 'LivingColors G2', + LLC006 => 'LivingColors Iris', + LLC007 => 'LivingColors Bloom', + LWB001 => 'LivingWhites Bulb', + LWL001 => 'LivingWhites Outlet', +); + +sub HUEDevice_Initialize($) +{ + my ($hash) = @_; + + # Provide + + #Consumer + $hash->{DefFn} = "HUEDevice_Define"; + $hash->{SetFn} = "HUEDevice_Set"; + $hash->{UndefFn} = "HUEDevice_Undefine"; + $hash->{AttrList} = "IODev ". + "$readingFnAttributes ". + "model:".join(",", sort keys %models)." ". + "subType:dimmer,switch"; +} + +sub HUEDevice_Define($$) +{ + my ($hash, $def) = @_; + + my @args = split("[ \t]+", $def); + + return "Usage: define HUEDevice [interval]" if(@args < 3); + + my ($name, $type, $id, $interval) = @args; + + $interval= 60 unless defined($interval); + if( $interval < 10 ) { $interval = 60; } + + + $hash->{STATE} = 'Initialized'; + $hash->{fhem}{interfaces}= "dimmer"; + + $hash->{fhem}{id} = $id; + $hash->{INTERVAL} = $interval; + + $hash->{fhem}{on} = -1; + $hash->{fhem}{colormode} = ''; + $hash->{fhem}{bri} = -1; + $hash->{fhem}{ct} = -1; + $hash->{fhem}{hue} = -1; + $hash->{fhem}{sat} = -1; + + AssignIoPort($hash); + if(defined($hash->{IODev}->{NAME})) { + Log 3, "$name: I/O device is " . $hash->{IODev}->{NAME}; + } else { + Log 1, "$name: no I/O device"; + } + + #HUEDevice_GetUpdate($hash); + InternalTimer(gettimeofday()+10, "HUEDevice_GetUpdate", $hash, 0); + + return undef; +} + +sub HUEDevice_Undefine($$) +{ + my ($hash,$arg) = @_; + + RemoveInternalTimer($hash); + + delete($hash->{fhem}{id}); + + return undef; +} + +sub +HUEDevice_Set($@) +{ + my ($hash, $name, $cmd, $value, $value2, @a) = @_; + + if( $cmd eq "color" ) { + $value = int(100000/$value); + $cmd = 'ct'; + } elsif( $cmd eq "toggle" ) { + $cmd = ReadingsVal($name,"state","on") eq "off" ? "on" :"off"; + } elsif( $cmd =~ m/^dim(\d+)/ ) { + $value = $1 unless defined($value); + if( $value < 0 ) { $value = 0; } + if( $value > 100 ) { $value = 100; } + $cmd = 'pct'; + } elsif( !defined($value) && $cmd =~ m/^(\d+)/) { + $value = $1; + if( $value > 254 ) { $value = 254; } + $cmd = 'bri'; + } + + # usage check + if($cmd eq 'statusRequest') { + RemoveInternalTimer($hash); + HUEDevice_GetUpdate($hash); + return undef; + } elsif($cmd eq 'on') { + + my $obj = { + 'on' => JSON::true, + }; + if( defined($value) ) { + $obj->{transitiontime} = $value / 10; + } + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq 'off') { + + my $obj = { + 'on' => JSON::false, + }; + if( defined($value) ) { + $obj->{transitiontime} = $value / 10; + } + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq "pct") { + my $obj = { + 'bri' => int(2.54 * $value), + 'on' => JSON::true, + }; + if( defined($value2) ) { + $obj->{transitiontime} = $value2 / 10; + } + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq "bri") { + my $obj = { + 'bri' => 0+$value, + 'on' => JSON::true, + }; + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq "ct") { + my $obj = { + 'ct' => 0+$value, + 'on' => JSON::true, + }; + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq "hue") { + my $obj = { + 'hue' => 0+$value, + 'on' => JSON::true, + }; + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + } elsif($cmd eq "sat") { + my $obj = { + 'sat' => 0+$value, + }; + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}."/state",$obj); + if( $result->{'error'} ) + { + $hash->{STATE} = $result->{'error'}->{'description'}; + return undef; + } + + } else { + my $list = "off on toggle statusRequest"; + $list .= " pct:slider,0,1,100 color:slider,2000,1,6500 bri:slider,0,1,254 ct:slider,154,1,500 hue:slider,0,1,65535 sat:slider,0,1,254" if( AttrVal($hash->{NAME}, "subType", "dimmer") eq "dimmer" ); + #$list .= " dim06% dim12% dim18% dim25% dim31% dim37% dim43% dim50% dim56% dim62% dim68% dim75% dim81% dim87% dim93% dim100%" if( AttrVal($hash->{NAME}, "subType", "dimmer") eq "dimmer" ); + return SetExtensions($hash, $list, $name, $cmd, $value, @a); + } + + $hash->{LOCAL} = 1; + HUEDevice_GetUpdate($hash); + delete $hash->{LOCAL}; + + return undef; +} + +################################### +# This could be IORead in fhem, But there is none. +# Read http://forum.fhem.de/index.php?t=tree&goto=54027&rid=10#msg_54027 +# to find out why. +sub +HUEDevice_ReadFromServer($@) +{ + my ($hash,@a) = @_; + + my $dev = $hash->{NAME}; + no strict "refs"; + my $ret; + unshift(@a,$dev); + $ret = IOWrite($hash, @a); + use strict "refs"; + return $ret; + return if(IsDummy($dev) || IsIgnored($dev)); + my $iohash = $hash->{IODev}; + if(!$iohash || + !$iohash->{TYPE} || + !$modules{$iohash->{TYPE}} || + !$modules{$iohash->{TYPE}}{ReadFn}) { + Log 5, "No I/O device or ReadFn found for $dev"; + return; + } + + no strict "refs"; + #my $ret; + unshift(@a,$dev); + $ret = &{$modules{$iohash->{TYPE}}{ReadFn}}($iohash, @a); + use strict "refs"; + return $ret; +} + +my %dim_values = ( + 0 => "dim06%", + 1 => "dim12%", + 2 => "dim18%", + 3 => "dim25%", + 4 => "dim31%", + 5 => "dim37%", + 6 => "dim43%", + 7 => "dim50%", + 8 => "dim56%", + 9 => "dim62%", + 10 => "dim68%", + 11 => "dim75%", + 12 => "dim81%", + 13 => "dim87%", + 14 => "dim93%", +); + + +sub +HUEDevice_GetUpdate($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + if(!$hash->{LOCAL}) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "HUEDevice_GetUpdate", $hash, 1); + } + + my $result = HUEDevice_ReadFromServer($hash,$hash->{fhem}{id}); + if( !defined($result) ) { + $hash->{STATE} = "unknown"; + return; + } elsif( $result->{'error'} ) { + $hash->{STATE} = $result->{'error'}->{'description'}; + return; + } + + $hash->{modelid} = $result->{'modelid'}; + $hash->{name} = $result->{'name'}; + $hash->{type} = $result->{'type'}; + $hash->{swversion} = $result->{'swversion'}; + + $attr{$name}{model} = $result->{'modelid'} unless (defined($attr{$name}{model}) || $result->{'modelid'} eq '' ); + + readingsBeginUpdate($hash); + + my $state = $result->{'state'}; + + my $on = $state->{on}; + my $colormode = $state->{'colormode'}; + my $bri = $state->{'bri'}; + my $ct = $state->{'ct'}; + my $hue = $state->{'hue'}; + my $sat = $state->{'sat'}; + + if( defined($colormode) && $colormode ne $hash->{fhem}{colormode} ) {readingsBulkUpdate($hash,"colormode",$colormode);} + if( defined($bri) && $bri != $hash->{fhem}{bri} ) {readingsBulkUpdate($hash,"bri",$bri);} + if( defined($ct) && $ct != $hash->{fhem}{ct} ) { + if( $ct == 0 ) { + readingsBulkUpdate($hash,"ct",$ct); + } + else { + readingsBulkUpdate($hash,"ct",$ct . " (".int(1000000/$ct)."K)"); + } + } + if( defined($hue) && $hue != $hash->{fhem}{hue} ) {readingsBulkUpdate($hash,"hue",$hue);} + if( defined($sat) && $sat != $hash->{fhem}{sat} ) {readingsBulkUpdate($hash,"sat",$sat);} + + my $s = ''; + if( $on ) + { + $s = 'on'; + if( $on != $hash->{fhem}{on} ) {readingsBulkUpdate($hash,"onoff",1);} + + my $percent = int( $state->{'bri'} * 100 / 254 ); + if( $bri != $hash->{fhem}{bri} ) {readingsBulkUpdate($hash,"level", $percent . ' %');} + if( $percent > 0 + && $percent < 100 ) { + $s = $dim_values{int($percent/7)}; + } + } + else + { + $s = 'off'; + if( $on != $hash->{fhem}{on} ) {readingsBulkUpdate($hash,"onoff",0);} + } + + if( $s ne $hash->{STATE} ) {readingsBulkUpdate($hash,"state",$s);} + readingsEndUpdate($hash,defined($hash->{LOCAL} ? 0 : 1)); + + $hash->{fhem}{on} = $on; + $hash->{fhem}{colormode} = $colormode; + $hash->{fhem}{bri} = $bri; + $hash->{fhem}{ct} = $ct; + $hash->{fhem}{hue} = $hue; + $hash->{fhem}{sat} = $sat; +} + +1; + +=pod +=begin html + + +

HUEDevice

+
    +
    + + Define +
      + define <name> HUEDevice <id> [<interval>]
      +
      + + Defines a device connected to a HUEBridge.

      + + This can be a hue bulb, a living color light or a living whites bulb or dimmer plug.

      + + The device status will be updated every <interval> seconds. The default and minimum is 60.

      + + Examples: +
        + define bulb HUEDevice 1
        + define LC HUEDevice 2
        +
      +

    + + + Readings +
      +
    • bri
      + the brightness reported from the device. the value can be betwen 1 and 254
    • +
    • colormode
      + the current colormode
    • +
    • ct
      + the colortemperature in mireds and kelvin
    • +
    • hue
      + the current hue
    • +
    • level
      + the current brightness in percent
    • +
    • onoff
      + the current on/off state as 0 or 1
    • +
    • sat
      + the current saturation
    • +
    • state
      + the current state
    • +
      + Notes: +
        +
      • not all readings show the actual device state. all readings not related to the current colormode have to be ignored.
      • +
      • the actual state of a device controlled by a living colors or living whites remote can be different and will + be updated after some time.
      • +

      +

    + + + Set +
      +
    • on [<ramp-time>]
    • +
    • off [<ramp-time>]
    • +
    • toggle [<ramp-time>]
    • +
    • statusRequest
      + Request device status update.
    • +
    • pct <value> [<ramp-time>]
      + dim to <value>
    • + Notes: +
        +
      • the FS20 compatible dimXX% commands are also accepted.
      • +

      +
    • color <value>
      + set colortemperature to <value> kelvin.
    • +
    • bri <value>
      + set brighness to <value>; range is 1-254.
    • +
    • ct <value>
      + set colortemperature to <value> mireds; range is 154-500.
    • +
    • hue <value>
      + set hue to <value>; range is 0-65535.
    • +
    • sat <value>
      + set saturation to <value>; range is 0-254.
    • +

    + + + Attributes +
      +
    • subType
      + dimmer or switch, default is dimmer.
    • +
    + +

+ +=end html +=cut