diff --git a/fhem/FHEM/70_PHTV.pm b/fhem/FHEM/70_PHTV.pm index 5da511031..5356a51c8 100644 --- a/fhem/FHEM/70_PHTV.pm +++ b/fhem/FHEM/70_PHTV.pm @@ -24,9 +24,12 @@ # along with fhem. If not, see . # # -# Version: 1.1.4 +# Version: 1.2.0 # # Major Version History: +# - 1.2.0 - 2014-03-12 +# -- extended AmbiHue support +# # - 1.1.0 - 2014-03-07 # -- bugfixes # -- additional commands: ambiMode,rgb,pause,play,record,volumeStraight @@ -42,6 +45,7 @@ package main; use strict; use warnings; use Data::Dumper; +use Time::HiRes qw(gettimeofday); use JSON; use HttpUtils; use Color; @@ -71,7 +75,7 @@ sub PHTV_Initialize($) { $hash->{UndefFn} = "PHTV_Undefine"; $hash->{AttrList} = -"disable:0,1 timeout inputs ambiHueLeft ambiHueRight ambiHueTop ambiHueBottom ambiHueLatency:100,125,150,175,200,225,250,275,300,325,350,375,400,425,450,475,500" +"disable:0,1 timeout inputs ambiHueLeft ambiHueRight ambiHueTop ambiHueBottom " . $readingFnAttributes; $data{RC_layout}{PHTV_SVG} = "PHTV_RClayout_SVG"; @@ -92,6 +96,10 @@ sub PHTV_GetStatus($;$) { Log3 $name, 5, "PHTV $name: called function PHTV_GetStatus()"; + $interval = $interval * 1.6 + if ( defined( $hash->{READINGS}{ambiHue}{VAL} ) + && $hash->{READINGS}{ambiHue}{VAL} eq "on" ); + RemoveInternalTimer($hash); InternalTimer( gettimeofday() + $interval, "PHTV_GetStatus", $hash, 0 ); @@ -266,8 +274,10 @@ sub PHTV_Set($@) { if ( defined( $hash->{helper}{device}{channelPreset} ) && ref( $hash->{helper}{device}{channelPreset} ) eq "HASH" ) { - my $i = 1; - while ( $i < 81 ) { + my $i = 1; + my $count = scalar( keys $hash->{helper}{device}{channelPreset} ); + $count = 80 if ( $count > 80 ); + while ( $i <= $count ) { $channels .= $hash->{helper}{device}{channelPreset}{$i}{name} . ","; $i++; @@ -283,7 +293,7 @@ sub PHTV_Set($@) { my $usage = "Unknown argument " . $a[1] - . ", choose one of statusRequest:noArg toggle:noArg on:noArg off:noArg play:noArg pause:noArg stop:noArg record:noArg volume:slider,1,1,100 volumeUp:noArg volumeDown:noArg channelUp:noArg channelDown:noArg remoteControl ambiHue:off,on ambiMode:internal,manual,expert ambiPreset:rainbow,rainbow-pastel rgb:colorpicker,rgb"; + . ", choose one of statusRequest:noArg toggle:noArg on:noArg off:noArg play:noArg pause:noArg stop:noArg record:noArg volume:slider,1,1,100 volumeUp:noArg volumeDown:noArg channelUp:noArg channelDown:noArg remoteControl ambiHue:off,on ambiMode:internal,manual,expert ambiPreset:rainbow,rainbow-pastel rgb:colorpicker,rgb hue:slider,0,1,65534 sat:slider,0,1,255 pct:slider,0,1,100 bri:slider,0,1,255"; $usage .= " volumeStraight:slider," . $hash->{helper}{audio}{min} . ",1," @@ -564,7 +574,7 @@ sub PHTV_Set($@) { # set all LEDs at once if ( uc( $a[2] ) =~ /^(..)(..)(..)$/ ) { my $json; - my $hsv; + my $hsb; my $hue; my $sat; my $bri; @@ -575,10 +585,10 @@ sub PHTV_Set($@) { $json .= '"r": ' . $r . ','; $json .= '"g": ' . $g . ','; $json .= '"b": ' . $b; - $hsv = PHTV_rgb2hsv( $r, $g, $b ); - $hue = $hsv->{h}; - $sat = int( $hsv->{s} * 100 + 0.5 ); - $bri = $hsv->{v}; + $hsb = PHTV_rgb2hsb( $r, $g, $b ); + $hue = $hsb->{h}; + $sat = $hsb->{s}; + $bri = $hsb->{b}; $pct = PHTV_bri2pct($bri); PHTV_SendCommand( $hash, "ambilight/cached", $json, uc( $a[2] ) ); @@ -696,7 +706,7 @@ sub PHTV_Set($@) { && $rgbsum > 0 ); } else { - return "Invalid RGB code"; + return "Invalid RGB code " . $a[2]; } } else { @@ -704,6 +714,119 @@ sub PHTV_Set($@) { } } + # hue + elsif ( $a[1] eq "hue" ) { + Log3 $name, 2, "PHTV set $name " . $a[1] . " " . $a[2]; + + return "No argument given" if ( !defined( $a[2] ) ); + + if ( $hash->{READINGS}{state}{VAL} eq "on" ) { + if ( defined( $hash->{READINGS}{rgb}{VAL} ) + && $hash->{READINGS}{rgb}{VAL} ne "" ) + { + my $_ = $a[2]; + my $hsb; + my $hex; + if ( m/^\d+$/ && $_ >= 0 && $_ <= 65534 ) { + $hsb = PHTV_hex2hsb( $hash->{READINGS}{rgb}{VAL} ); + $hex = PHTV_hsb2hex( $_, $hsb->{s}, $hsb->{b} ); + + Log3 $name, 4, + "PHTV $name hue - old: " + . $hash->{READINGS}{rgb}{VAL} + . " new: $hex(h=$_ s=" + . $hsb->{s} . " b=" + . $hsb->{b}; + + return PHTV_Set( $hash, $name, "rgb", $hex ); + } + else { + return +"Argument does not seem to be a valid integer between 0 and 100"; + } + } + } + else { + return "Device needs to be ON to set Ambilight color."; + } + } + + # sat + elsif ( $a[1] eq "sat" ) { + Log3 $name, 2, "PHTV set $name " . $a[1] . " " . $a[2]; + + return "No argument given" if ( !defined( $a[2] ) ); + + if ( $hash->{READINGS}{state}{VAL} eq "on" ) { + if ( defined( $hash->{READINGS}{rgb}{VAL} ) + && $hash->{READINGS}{rgb}{VAL} ne "" ) + { + my $_ = $a[2]; + my $hsb; + my $hex; + if ( m/^\d+$/ && $_ >= 0 && $_ <= 255 ) { + $hsb = PHTV_hex2hsb( $hash->{READINGS}{rgb}{VAL} ); + $hex = PHTV_hsb2hex( $hsb->{h}, $_, $hsb->{b} ); + + Log3 $name, 4, + "PHTV $name sat - old: " + . $hash->{READINGS}{rgb}{VAL} + . " new: $hex(h=" + . $hsb->{h} + . " s=$_ b=" + . $hsb->{b}; + + return PHTV_Set( $hash, $name, "rgb", $hex ); + } + else { + return +"Argument does not seem to be a valid integer between 0 and 100"; + } + } + } + else { + return "Device needs to be ON to set Ambilight color."; + } + } + + # bri + elsif ( $a[1] eq "bri" ) { + Log3 $name, 2, "PHTV set $name " . $a[1] . " " . $a[2]; + + return "No argument given" if ( !defined( $a[2] ) ); + + if ( $hash->{READINGS}{state}{VAL} eq "on" ) { + if ( defined( $hash->{READINGS}{rgb}{VAL} ) + && $hash->{READINGS}{rgb}{VAL} ne "" ) + { + my $_ = $a[2]; + my $hsb; + my $hex; + if ( m/^\d+$/ && $_ >= 0 && $_ <= 255 ) { + $hsb = PHTV_hex2hsb( $hash->{READINGS}{rgb}{VAL} ); + $hex = PHTV_hsb2hex( $hsb->{h}, $hsb->{s}, $_ ); + + Log3 $name, 4, + "PHTV $name bri - old: " + . $hash->{READINGS}{rgb}{VAL} + . " new: $hex(h=" + . $hsb->{h} . " s=" + . $hsb->{s} + . " b=$_)"; + + return PHTV_Set( $hash, $name, "rgb", $hex ); + } + else { + return +"Argument does not seem to be a valid integer between 0 and 100"; + } + } + } + else { + return "Device needs to be ON to set Ambilight color."; + } + } + # pct elsif ( $a[1] eq "pct" ) { Log3 $name, 2, "PHTV set $name " . $a[1] . " " . $a[2]; @@ -715,12 +838,23 @@ sub PHTV_Set($@) { && $hash->{READINGS}{rgb}{VAL} ne "" ) { my $_ = $a[2]; - my $rgb; - my $rgbnew; + my $hsb; + my $bri; + my $hex; if ( m/^\d+$/ && $_ >= 0 && $_ <= 100 ) { - $rgb = PHTV_hex2hsv( $hash->{READINGS}{rgb}{VAL} ); - $rgbnew = PHTV_hsv2hex( $rgb->{h}, $rgb->{s}, $_ ); - return PHTV_Set( $hash, $name, "rgb", $rgbnew ); + $hsb = PHTV_hex2hsb( $hash->{READINGS}{rgb}{VAL} ); + $bri = PHTV_pct2bri($_); + $hex = PHTV_hsb2hex( $hsb->{h}, $hsb->{s}, $bri ); + + Log3 $name, 4, + "PHTV $name pct - old: " + . $hash->{READINGS}{rgb}{VAL} + . " new: $hex(h=" + . $hsb->{h} . " s=" + . $hsb->{s} + . " b=$bri)"; + + return PHTV_Set( $hash, $name, "rgb", $hex ); } else { return @@ -1107,8 +1241,8 @@ sub PHTV_Define($$) { $hash->{helper}{PORT} = 1925; - readingsSingleUpdate( $hash, "ambiHue", "off", 0 ); - if ( defined( $hash->{READINGS}{ambiHue}{VAL} ) + readingsSingleUpdate( $hash, "ambiHue", "off", 0 ) + if ( defined( $hash->{READINGS}{ambiHue}{VAL} ) && $hash->{READINGS}{ambiHue}{VAL} ne "off" ); $hash->{model} = $hash->{READINGS}{model}{VAL} @@ -1144,9 +1278,10 @@ sub PHTV_Define($$) { ################################### sub PHTV_SendCommand($$;$$) { my ( $hash, $service, $cmd, $type ) = @_; - my $name = $hash->{NAME}; - my $address = $hash->{helper}{ADDRESS}; - my $port = $hash->{helper}{PORT}; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $port = $hash->{helper}{PORT}; + my $timestamp = gettimeofday(); my $data; my $timeout; @@ -1207,6 +1342,7 @@ sub PHTV_SendCommand($$;$$) { service => $service, cmd => $cmd, type => $type, + timestamp => $timestamp, callback => \&PHTV_ReceiveCommand, } ); @@ -1221,6 +1357,7 @@ sub PHTV_ReceiveCommand($$$) { my $name = $hash->{NAME}; my $service = $param->{service}; my $cmd = $param->{cmd}; + my $state = ( $hash->{READINGS}{state}{VAL} ) ? $hash->{READINGS}{state}{VAL} @@ -1909,7 +2046,7 @@ sub PHTV_ReceiveCommand($$$) { # ambilight/cached (rgb) elsif ( $service eq "ambilight/cached" ) { if ( ref($return) eq "HASH" ) { - my $rgb = ""; + my $hexsum = ""; foreach my $layer ( keys $return ) { foreach my $side ( keys $return->{$layer} ) { foreach my $led ( keys $return->{$layer}{$side} ) { @@ -1929,8 +2066,8 @@ sub PHTV_ReceiveCommand($$$) { $return->{$layer}{$side}{$led}{b} ); - $rgb = $hex if ( $rgb eq "" ); - $rgb = "diff" if ( $rgb ne $hex ); + $hexsum = $hex if ( $hexsum eq "" ); + $hexsum = "diff" if ( $hexsum ne $hex ); if ( !defined( @@ -1945,17 +2082,17 @@ sub PHTV_ReceiveCommand($$$) { } } - if ( $rgb ne "diff" ) { - my $hsv = PHTV_hex2hsv($rgb); - my $hue = $hsv->{h}; - my $sat = int( $hsv->{s} * 100 + 0.5 ); - my $bri = $hsv->{v}; + if ( $hexsum ne "diff" ) { + my $hsb = PHTV_hex2hsb($hexsum); + my $hue = $hsb->{h}; + my $sat = $hsb->{s}; + my $bri = $hsb->{b}; my $pct = PHTV_bri2pct($bri); if ( !defined( $hash->{READINGS}{rgb}{VAL} ) - || $hash->{READINGS}{rgb}{VAL} ne $rgb ) + || $hash->{READINGS}{rgb}{VAL} ne $hexsum ) { - readingsBulkUpdate( $hash, "rgb", $rgb ); + readingsBulkUpdate( $hash, "rgb", $hexsum ); } if ( !defined( $hash->{READINGS}{hue}{VAL} ) @@ -1988,10 +2125,10 @@ sub PHTV_ReceiveCommand($$$) { if ( $type =~ /^(..)(..)(..)$/ && defined( $hash->{READINGS}{ambiLEDLayers}{VAL} ) ) { - my $hsv = PHTV_hex2hsv($type); - my $hue = $hsv->{h}; - my $sat = int( $hsv->{s} * 100 + 0.5 ); - my $bri = $hsv->{v}; + my $hsb = PHTV_hex2hsb($type); + my $hue = $hsb->{h}; + my $sat = $hsb->{s}; + my $bri = $hsb->{b}; my $pct = PHTV_bri2pct($bri); if ( !defined( $hash->{READINGS}{rgb}{VAL} ) @@ -2103,92 +2240,148 @@ sub PHTV_ReceiveCommand($$$) { foreach my $side ( 'Left', 'Top', 'Right', 'Bottom' ) { my $ambiHue = "ambiHue$side"; my $ambiLED = "ambiLED$side"; - my $sidelc = lc($side); + my $s = lc($side); # $ambiHue if ( defined( $attr{$name}{$ambiHue} ) && $attr{$name}{$ambiHue} ne "" - && defined( $return->{layer1}->{$sidelc} ) - && ref( $return->{layer1}->{$sidelc} ) eq "HASH" ) + && defined( $return->{layer1}->{$s} ) + && ref( $return->{layer1}->{$s} ) eq "HASH" + && defined( $hash->{READINGS}{$ambiLED}{VAL} ) + && $hash->{READINGS}{$ambiLED}{VAL} > 0 ) { my @devices = split( " ", $attr{$name}{$ambiHue} ); foreach my $devled (@devices) { - my ( $dev, $led ) = split( /:/, $devled ); + my ( $dev, $led, $sat, $bri ) = + split( /:/, $devled ); + my @leds; - # determine reference LED + # next for if HUE device is not ready + if ( !defined( $defs{$dev} ) + || !defined( $defs{$dev}{TYPE} ) + || $defs{$dev}{TYPE} ne "HUEDevice" + || $defs{$dev}{READINGS}{reachable}{VAL} ne + "true" ) + { + next; + } + + # determine reference LEDs if ( !defined($led) || $led eq "" ) { - if ( - defined( - $hash->{READINGS}{$ambiLED}{VAL} + my $led_middle = int( + $hash->{READINGS}{$ambiLED}{VAL} / 2 + + 0.5 ) - 1; + + # take the middle LED and + # one left and right each + push( + @leds, + ( + $led_middle, + $led_middle - 1, + $led_middle + 1 ) - && $hash->{READINGS}{$ambiLED}{VAL} > 0 - ) - { - $led = int( - $hash->{READINGS}{$ambiLED}{VAL} / - 2 + 0.5 ) - 1; + ); + } + + # user named reference LED(s) + else { + my ( $ledB, $ledE ) = split( /-/, $led ); + $ledB -= 1; + $ledE -= 1 + if ( defined($ledE) && $ledE ne "" ); + + if ( !defined($ledE) || $ledE eq "" ) { + push( @leds, ($ledB) ); } else { - $led = ""; + my $i = $ledB; + while ( $i <= $ledE ) { + push( @leds, ($i) ); + $i++; + } } } - # copy color from reference LED - if ( - defined( $defs{$dev} && $led ne "" ) - && $defs{$dev}{TYPE} eq "HUEDevice" - && defined( - $return->{layer1}->{$sidelc}->{$led} - ->{r} - ) - && defined( - $return->{layer1}->{$sidelc}->{$led} - ->{g} - ) - && defined( - $return->{layer1}->{$sidelc}->{$led} - ->{b} - ) - ) - { - my $r = sprintf( "%02x", - $return->{layer1}->{$sidelc}->{$led} - ->{r} ); - my $g = sprintf( "%02x", - $return->{layer1}->{$sidelc}->{$led} - ->{g} ); - my $b = sprintf( "%02x", - $return->{layer1}->{$sidelc}->{$led} - ->{b} ); - - # temp. disable event triggers for HUEDevice + # get current RGB values + my ( $Hsum, $Ssum, $Bsum ); + foreach my $l (@leds) { if ( - !defined( - $attr{$dev} - {"event-on-change-reading"} + defined( + $return->{layer1}->{$s}->{$l} ) - || $attr{$dev} - {"event-on-change-reading"} ne "none" ) { - $attr{$dev}{"event-on-change-reading"} - = "none"; - } - # send command - fhem("set $dev rgb $r$g$b"); + my $hsb = PHTV_rgb2hsb( + $return->{layer1}->{$s}->{$l}->{r}, + $return->{layer1}->{$s}->{$l}->{g}, + $return->{layer1}->{$s}->{$l}->{b} + ); + + $Hsum += $hsb->{h}; + $Ssum += $hsb->{s}; + $Bsum += $hsb->{b}; + } } + + # consider user defined values + my $satF = + ( $sat && $sat > 0 && $sat < 100 ) + ? $sat / 100 + : 1; + my $briF = + ( $bri && $bri > 0 && $bri < 100 ) + ? $bri / 100 + : 1; + + my $countLEDs = scalar @leds; + my $h = sprintf( "%02x", + int( $Hsum / $countLEDs / 256 + 0.5 ) ); + my $s = sprintf( "%02x", + int( $Ssum / $countLEDs * $satF + 0.5 ) ); + my $b = sprintf( "%02x", + int( $Bsum / $countLEDs * $briF + 0.5 ) ); + + # temp. disable event triggers for HUEDevice + if ( + !defined( + $attr{$dev}{"event-on-change-reading"} + ) + || $attr{$dev}{"event-on-change-reading"} + ne "none" + ) + { + $attr{$dev}{"event-on-change-reading"} = + "none"; + } + + $hash->{helper}{ambiHueColor} = "$h$s$b"; + + # switch HUE to color + if ( $b ne "00" ) { + fhem( +"set $dev transitiontime 1 : noUpdate : hsv $h$s$b" + ); + } + + # switch HUE off if brightness is 0 + else { + fhem( +"set $dev transitiontime 0 : noUpdate : off" + ); + } + } } } - my $latency = - ( $attr{$name}{ambiHueLatency} ) - ? $attr{$name}{ambiHueLatency} / 100 - : 0.2; - fhem("sleep $latency"); + $hash->{helper}{ambiHueDelay} = + int( + ( gettimeofday() - $param->{timestamp} ) * 1000 + 0.5 ); + PHTV_SendCommand( $hash, "ambilight/processed" ); } @@ -2201,6 +2394,8 @@ sub PHTV_ReceiveCommand($$$) { && !defined( $attr{$name}{ambiHueBottom} ) ) ) { + delete $hash->{helper}{ambiHueDelay}; + delete $hash->{helper}{ambiHueColor}; readingsBulkUpdate( $hash, "ambiHue", "off" ) if ( $hash->{READINGS}{ambiHue}{VAL} ne "off" ); @@ -2566,6 +2761,20 @@ sub PHTV_isinteger { defined $_[0] && $_[0] =~ /^[+-]?\d+$/; } +################################### +sub PHTV_bri2pct($) { + my ($bri) = @_; + return 0 if ( $bri <= 0 ); + return int( $bri / 255 * 100 + 0.5 ); +} + +################################### +sub PHTV_pct2bri($) { + my ($pct) = @_; + return 0 if ( $pct <= 0 ); + return int( $pct / 100 * 255 + 0.5 ); +} + ################################### sub PHTV_hex2rgb($) { my ($hex) = @_; @@ -2590,16 +2799,16 @@ sub PHTV_rgb2hex($$$) { } ################################### -sub PHTV_hex2hsv($;$) { +sub PHTV_hex2hsb($;$) { my ( $hex, $type ) = @_; $type = lc($type) if ( defined( ($type) && $type ne "" ) ); my $rgb = PHTV_hex2rgb($hex); - my $return = PHTV_rgb2hsv( $rgb->{r}, $rgb->{g}, $rgb->{b} ); + my $return = PHTV_rgb2hsb( $rgb->{r}, $rgb->{g}, $rgb->{b} ); if ( defined($type) ) { return $return->{h} if ( $type eq "h" ); return $return->{s} if ( $type eq "s" ); - return $return->{v} if ( $type eq "v" ); + return $return->{b} if ( $type eq "b" ); } else { return $return; @@ -2607,113 +2816,136 @@ sub PHTV_hex2hsv($;$) { } ################################### -sub PHTV_bri2pct($) { - my ($bri) = @_; - return 0 if ( $bri <= 0 ); - return int( ( $bri / 255 * 100 ) + 0.5 ); -} - -################################### -sub PHTV_pct2bri($) { - my ($pct) = @_; - return 0 if ( $pct <= 0 ); - return int( ( $pct / 100 * 255 ) + 0.5 ); -} - -################################### -sub PHTV_hsv2hex($$$) { - my ( $h, $s, $v ) = @_; - my $rgb = PHTV_hsv2rgb( $h, $s, $v ); +sub PHTV_hsb2hex($$$) { + my ( $h, $s, $b ) = @_; + my $rgb = PHTV_hsb2rgb( $h, $s, $b ); return PHTV_rgb2hex( $rgb->{r}, $rgb->{g}, $rgb->{b} ); } ################################### -sub PHTV_rgb2hsv($$$;$) { - my ( $r, $g, $b, $type ) = @_; - $type = lc($type) if ( defined( ($type) && $type ne "" ) ); - my ( $M, $m, $C, $H, $S, $V ); +sub PHTV_rgb2hsb ($$$) { + my ( $r, $g, $b ) = @_; + + my $r2 = $r / 255.0; + my $g2 = $g / 255.0; + my $b2 = $b / 255.0; + + my $hsv = PHTV_rgb2hsv( $r2, $g2, $b2 ); + my $h = int( $hsv->{h} * 65535 ); + my $s = int( $hsv->{s} * 255 ); + my $bri = int( $hsv->{v} * 255 ); + + Log3 undef, 5, "PHTV rgb2hsb: $r $g $b > $h $s $bri"; + + return { "h" => $h, "s" => $s, "b" => $bri }; +} + +################################### +sub PHTV_hsb2rgb ($$$) { + my ( $h, $s, $bri ) = @_; + + my $h2 = $h / 65535.0; + my $s2 = $s / 255.0; + my $bri2 = $bri / 255.0; + + my $rgb = PHTV_hsv2rgb( $h2, $s2, $bri2 ); + my $r = int( $rgb->{r} * 255 ); + my $g = int( $rgb->{g} * 255 ); + my $b = int( $rgb->{b} * 255 ); + + Log3 undef, 5, "PHTV hsb2rgb: $h $s $bri > $r $g $b"; + + return { "r" => $r, "g" => $g, "b" => $b }; +} + +################################### +sub PHTV_rgb2hsv($$$) { + my ( $r, $g, $b ) = @_; + my ( $M, $m, $c, $h, $s, $v ); $M = PHTV_max( $r, $g, $b ); $m = PHTV_min( $r, $g, $b ); - $C = ( $M - $m ) if ( $M > 0 || $m > 0 ); - $C = 0 if ( $M == 0 && $m == 0 ); + $c = $M - $m; - if ( $C == 0 ) { - $H = 0; - $S = 0; + if ( $c == 0 ) { + $h = 0; + } + elsif ( $M == $r ) { + $h = ( 60 * ( ( $g - $b ) / $c ) % 360 ) / 360; + } + elsif ( $M == $g ) { + $h = ( 60 * ( ( $b - $r ) / $c ) + 120 ) / 360; + } + elsif ( $M == $b ) { + $h = ( 60 * ( ( $r - $g ) / $c ) + 240 ) / 360; + } + + if ( $M == 0 ) { + $s = 0; } else { - if ( $r == $M ) { - $H = ( $g - $b ) / $C; - $H += 6.0 - if ( $H < 0.0 ); - } - elsif ( $g == $M ) { - $H = ( ( $b - $r ) / $C ) + 2.0; - } - elsif ( $b == $M ) { - $H = ( ( $r - $g ) / $C ) + 4.0; - } - - $H *= 60.0; - $S = $C / $M; + $s = $c / $M; } + $v = $M; - $V = $M; + Log3 undef, 5, "PHTV rgb2hsv: $r $g $b > $h $s $v"; - Log3 undef, 5, "PHTV rgb2hsv: $r $g $b > $H $S $V"; - - if ( defined($type) ) { - return $H if ( $type eq "h" ); - return $S if ( $type eq "s" ); - return $V if ( $type eq "v" ); - } - else { - return { "h" => $H, "s" => $S, "v" => $V }; - } + return { "h" => $h, "s" => $s, "v" => $v }; } ################################### sub PHTV_hsv2rgb($$$) { - my ( $H, $S, $V ) = @_; - my ( $r, $g, $b, $C, $Hdash, $X, $m ); + my ( $h, $s, $v ) = @_; + my $r = 0.0; + my $g = 0.0; + my $b = 0.0; - $C = $S * $V; - $Hdash = $H / 60.0; - $X = $C * ( 1.0 - int( ( $Hdash % 2.0 ) - 1.0 ) ); + if ( $s == 0 ) { + $r = $v; + $g = $v; + $b = $v; + } + else { + my $i = int( $h * 6.0 ); + my $f = ( $h * 6.0 ) - $i; + my $p = $v * ( 1.0 - $s ); + my $q = $v * ( 1.0 - $s * $f ); + my $t = $v * ( 1.0 - $s * ( 1.0 - $f ) ); + $i = $i % 6; - if ( $Hdash < 1.0 ) { - $r = $C; - $g = $X; - } - elsif ( $Hdash < 2.0 ) { - $r = $X; - $g = $C; - } - elsif ( $Hdash < 3.0 ) { - $g = $C; - $b = $X; - } - elsif ( $Hdash < 4.0 ) { - $g = $X; - $b = $C; - } - elsif ( $Hdash < 5.0 ) { - $r = $X; - $b = $C; - } - elsif ( $Hdash <= 6.0 ) { - $r = $C; - $b = $X; + if ( $i == 0 ) { + $r = $v; + $g = $t; + $b = $p; + } + elsif ( $i == 1 ) { + $r = $q; + $g = $v; + $b = $p; + } + elsif ( $i == 2 ) { + $r = $p; + $g = $v; + $b = $t; + } + elsif ( $i == 3 ) { + $r = $p; + $g = $q; + $b = $v; + } + elsif ( $i == 4 ) { + $r = $t; + $g = $p; + $b = $v; + } + elsif ( $i == 5 ) { + $r = $v; + $g = $p; + $b = $q; + } } - $m = $V - $C; - - $r += $m; - $g += $m; - $b += $m; - - Log3 undef, 5, "PHTV hsv2rgb: $H $S $V > $r $g $b"; + Log3 undef, 5, "PHTV hsv2rgb: $h $s $v > $r $g $b"; return { "r" => $r, "g" => $g, "b" => $b }; } @@ -2722,7 +2954,8 @@ sub PHTV_hsv2rgb($$$) { sub PHTV_max { my ( $max, @vars ) = @_; for (@vars) { - $max = $_ if $_ > $max; + $max = $_ + if $_ > $max; } return $max; } @@ -2792,6 +3025,9 @@ sub PHTV_min {
  • ambiMode internal,manual,expert   -   set source register for Ambilight
  • ambiPreset   -   set Ambilight to predefined state
  • rgb HEX,LED address   -   set an RGB value for Ambilight
  • +
  • hue 0-65534   -   set the color hue value Ambilight
  • +
  • sat 0-255   -   set the saturation value for Ambilight
  • +
  • bri 0-255   -   set the brightness value for Ambilight
  • play   -   starts/resumes playback
  • pause   -   starts/resumes playback
  • stop   -   stops current playback
  • @@ -2826,6 +3062,44 @@ sub PHTV_min {

    +
    +
    + +
    + Advanced Ambilight+HUE Control
    +
    +
    + Linking to your HUE devices within attributes ambiHueLeft, ambiHueTop, ambiHueRight and ambiHueBottom uses some defaults to calculate the actual color.
    + The following settings can be fine tuned:
    +
    +
  • LED(s) to be used as color source
    + either 1 single LED or a few in a raw like 2-4. Defaults to use the middle LED and it's left and right partners. Counter starts at 1. See readings ambiLED* for how many LED's your TV has.
  • +
  • saturation in percent of the original value (1-99, default=100)
  • +
  • brightness in percent of the original value (1-99, default=100)
  • +

    + Use the following addressing format for fine tuning:
    + devicename:<LEDs$gt;<saturation$gt;<brightness$gt; +

    + Examples:
    +
    + # to use only LED 4 from the top as source + attr PhilipsTV ambiHueTop HUEDevice0:4

    + # to use a combination of LED's 1+2 as source + attr PhilipsTV ambiHueTop HUEDevice0:1-2

    + # to use LED's 1+2 and only 90% of their saturation + attr PhilipsTV ambiHueTop HUEDevice0:1-2:90

    + # to use LED's 1+2 and only 50% of their brightness + attr PhilipsTV ambiHueTop HUEDevice0:1-2::50

    + # to use LED's 1+2, 90% saturation and 50% brightness + attr PhilipsTV ambiHueTop HUEDevice0:1-2:90:50 + # to use default LED settings but only adjust their brightness to 50% + attr PhilipsTV ambiHueTop HUEDevice0:::50
    +

    +
    +
    +
    +
    + Get