From b3305db5c192ba4b609f43943ff23c9da126c16d Mon Sep 17 00:00:00 2001
From: mattwire
Date: Tue, 5 May 2015 11:06:05 +0000
Subject: [PATCH] 31_MilightDevice: Fixes, features, changes by MarkusM
git-svn-id: https://svn.fhem.de/fhem/trunk@8528 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 1 +
fhem/FHEM/30_MilightBridge.pm | 19 +-
fhem/FHEM/31_MilightDevice.pm | 875 ++++++++++++++++++++++++----------
3 files changed, 646 insertions(+), 249 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index faca9e748..674aaa615 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# 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.
+ - change: MilightDevice/MilightBridge: Fixes, features, changes (by MarkusM)
- bugfix: SYSMON: network speed
- improved: I2C_TSL2561: asynchronous measurements, new readings (by jensb),
new set update command, removed get command
diff --git a/fhem/FHEM/30_MilightBridge.pm b/fhem/FHEM/30_MilightBridge.pm
index 87919590d..ec71b815c 100644
--- a/fhem/FHEM/30_MilightBridge.pm
+++ b/fhem/FHEM/30_MilightBridge.pm
@@ -47,7 +47,7 @@ sub MilightBridge_Initialize($)
$hash->{UndefFn} = "MilightBridge_Undefine";
$hash->{NotifyFn} = "MilightBridge_Notify";
$hash->{AttrFn} = "MilightBridge_Attr";
- $hash->{AttrList} = "port sendInterval disable:0,1 ".$readingFnAttributes;
+ $hash->{AttrList} = "port sendInterval disable:0,1 checkInterval ".$readingFnAttributes;
return undef;
}
@@ -96,6 +96,7 @@ sub MilightBridge_Define($$)
# Set Attributes
$attr{$name}{"event-on-change-reading"} = "state" if (!defined($attr{$name}{"event-on-change-reading"}));
+ $attr{$name}{"checkInterval"} = 10 if (!defined($attr{$name}{"checkInterval"}));
# Set state
$hash->{SENDFAIL} = 0;
@@ -136,6 +137,14 @@ sub MilightBridge_Attr($$$$) {
$hash->{INTERVAL} = $attr{$name}{"sendInterval"};
}
}
+ if ($attribute eq "checkInterval")
+ {
+ if (($value !~ /^\d*$/) || ($value < 5))
+ {
+ $attr{$name}{"checkInterval"} = 10;
+ return "checkInterval is required in s (default: 10, min: 5)";
+ }
+ }
elsif ($attribute eq "port")
{
if (($value !~ /^\d*$/) || ($value < 1))
@@ -208,8 +217,8 @@ sub MilightBridge_State(@)
# Update send fail flag
readingsSingleUpdate( $hash, "sendFail", $hash->{SENDFAIL}, 1 );
- # Check state every 10 seconds
- InternalTimer(gettimeofday() + 10, "MilightBridge_State", $hash, 0);
+ # Check state every X seconds
+ InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, "checkInterval", "10"), "MilightBridge_State", $hash, 0);
return undef;
}
@@ -381,6 +390,10 @@ sub MilightBridge_CmdQueue_Send(@)
sendInterval
Default: 100ms. The bridge has a minimum send delay of 100ms between commands.
+
+ checkInterval
+ Default: 10s. Time after the bridge connection is re-checked.
+
port
Default: 8899. Older bridges (V2) used port 50000 so change this value if you have an old bridge.
diff --git a/fhem/FHEM/31_MilightDevice.pm b/fhem/FHEM/31_MilightDevice.pm
index b3483218e..629e8c9f8 100644
--- a/fhem/FHEM/31_MilightDevice.pm
+++ b/fhem/FHEM/31_MilightDevice.pm
@@ -51,9 +51,10 @@ my %dim_values = (
);
# RGBW 3 byte commands. 3rd byte not required Bridge V3+
-my @RGBWCmdsOn = ("\x45", "\x47", "\x49", "\x4B"); # Byte 1 for setting On
-my @RGBWCmdsOff = ("\x46", "\x48", "\x4A", "\x4C"); # Byte 1 for setting Off
-my @RGBWCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB"); # Byte 1 for setting WhiteMode
+my @RGBWCmdsOn = ("\x45", "\x47", "\x49", "\x4B", "\x42"); # Byte 1 for setting On
+my @RGBWCmdsOff = ("\x46", "\x48", "\x4A", "\x4C", "\x41"); # Byte 1 for setting Off
+my @RGBWCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB", "\xC2"); # Byte 1 for setting WhiteMode
+my @RGBWCmdsNt = ("\xC6", "\xC8", "\xCA", "\xCC", "\xC1"); # Byte 1 for setting NightMode
my $RGBWCmdBri = "\x4E"; # Byte 1 for setting brightness (Byte 2 specifies level (0x02-0x1B 25 steps)
my $RGBWCmdCol = "\x40"; # Byte 1 for setting color (Byte 2 specifies color value (0x00-0xFF (255 steps))
my $RGBWCmdDiscoUp = "\x4D"; # Byte 1 for setting discoMode Up
@@ -62,13 +63,14 @@ my $RGBWCmdDiscoDec = "\x43"; # Byte 1 for setting discoMode speed -
my $RGBWCmdEnd = "\x55"; # Byte 3
# White 3 byte commands.
-my @WhiteCmdsOn = ("\x38", "\x3D", "\x37", "\x32"); # Byte 1 for setting On
-my @WhiteCmdsOff = ("\x3B", "\x33", "\x3A", "\x36"); # Byte 1 for setting Off
-my @WhiteCmdsOnFull = ("\xB8", "\xBD", "\xB7", "\xB2"); # Byte 1 for setting full brightness
-my $WhiteCmdBriDn = "\x34"; # Byte 1 for setting Brightness down (10 steps, no direct setting)
-my $WhiteCmdBriUp = "\x3C"; # Byte 1 for setting Brightness up (10 steps, no direct setting)
-my $WhiteCmdColDn = "\x3F"; # Byte 1 for setting colour temp down
-my $WhiteCmdColUp = "\x3E"; # Byte 1 for setting colour temp up
+my @WhiteCmdsOn = ("\x38", "\x3D", "\x37", "\x32", "\x35"); # Byte 1 for setting On
+my @WhiteCmdsOff = ("\x3B", "\x33", "\x3A", "\x36", "\x39"); # Byte 1 for setting Off
+my @WhiteCmdsOnFull = ("\xB8", "\xBD", "\xB7", "\xB2", "\xB5"); # Byte 1 for setting full brightness
+my @WhiteCmdsNt = ("\xBB", "\xB3", "\xBA", "\xB6", "\xB9"); # Byte 1 for setting NightMode
+my @WhiteCmdBriDn = ("\x34", "\x34", "\x34", "\x34", "\xB4"); # Byte 1 for setting Brightness down (11 steps, no direct setting)
+my @WhiteCmdBriUp = ("\x3C", "\x3C", "\x3C", "\x3C", "\xBC"); # Byte 1 for setting Brightness up (11 steps, no direct setting)
+my @WhiteCmdColDn = ("\x3F", "\x3F", "\x3F", "\x3F", "\xBF"); # Byte 1 for setting colour temp down
+my @WhiteCmdColUp = ("\x3E", "\x3E", "\x3E", "\x3E", "\xBE"); # Byte 1 for setting colour temp up
my $WhiteCmdEnd = "\x55"; # Byte 3
@@ -83,8 +85,7 @@ sub MilightDevice_Initialize(@)
$hash->{GetFn} = "MilightDevice_Get";
$hash->{AttrFn} = "MilightDevice_Attr";
$hash->{NotifyFn} = "MilightDevice_Notify";
- $hash->{AttrList} = "IODev dimStep defaultRampOn defaultRampOff presets ".$readingFnAttributes;
-
+ $hash->{AttrList} = "IODev dimStep defaultBrightness defaultRampOn defaultRampOff presets dimOffWhite:1,0 updateGroupDevices:1,0 colorCast gamma lightSceneParamsToSave ".$readingFnAttributes;
FHEM_colorpickerInit();
return undef;
@@ -106,7 +107,7 @@ sub MilightDevice_devStateIcon($)
my $s = $dim_values{round($percent/10)};
# Return SVG coloured icon with toggle as default action
- return ".*:light_light_$s@#".ReadingsVal($name, "RGB", "FFFFFF").":toggle"
+ return ".*:light_light_$s@#".ReadingsVal($name, "rgb", "FFFFFF").":toggle"
if (($hash->{LEDTYPE} eq 'RGBW') || ($hash->{LEDTYPE} eq 'RGB'));
# Return SVG icon with toggle as default action (for White bulbs)
return ".*:light_light_$s:toggle";
@@ -122,13 +123,18 @@ sub MilightDevice_Define($$)
$hash->{LEDTYPE} = $ledtype;
$hash->{SLOT} = $slot;
+ $hash->{SLOTID} = $slot;
+ if($slot eq 'A') {
+ $hash->{SLOTID} = 9 if ($hash->{LEDTYPE} eq 'RGBW');
+ $hash->{SLOTID} = 5 if ($hash->{LEDTYPE} eq 'White');
+ }
# Validate parameters
return "wrong syntax: define MilightDevice " if(@args < 5);
return "unknown LED type ($hash->{LEDTYPE}): choose one of RGB, RGBW, White" if !($hash->{LEDTYPE} ~~ ['RGB', 'RGBW', 'White']);
- return "Invalid slot: Select one of 1..4 for White" if (($hash->{SLOT} !~ /^\d*$/) || (($hash->{SLOT} < 1) || ($hash->{SLOT} > 4)) && ($hash->{LEDTYPE} eq 'White'));
- return "Invalid slot: Select one of 5..8 for RGBW" if (($hash->{SLOT} !~ /^\d*$/) || (($hash->{SLOT} < 5) || ($hash->{SLOT} > 8)) && ($hash->{LEDTYPE} eq 'RGBW'));
- return "Invalid slot: Select 0 for RGB" if (($hash->{SLOT} !~ /^\d*$/) || ($hash->{SLOT} != 0) && ($hash->{LEDTYPE} eq 'RGB'));
+ return "Invalid slot: Select one of 1..4 / A for White" if (($hash->{SLOTID} !~ /^\d*$/) || (($hash->{SLOT} ne 'A') && (($hash->{SLOT} < 1) || ($hash->{SLOT} > 4))) && ($hash->{LEDTYPE} eq 'White'));
+ return "Invalid slot: Select one of 5..8 / A for RGBW" if (($hash->{SLOTID} !~ /^\d*$/) || (($hash->{SLOT} ne 'A') && (($hash->{SLOT} < 5) || ($hash->{SLOT} > 8))) && ($hash->{LEDTYPE} eq 'RGBW'));
+ return "Invalid slot: Select 0 for RGB" if (($hash->{SLOTID} !~ /^\d*$/) || ($hash->{SLOT} != 0) && ($hash->{LEDTYPE} eq 'RGB'));
Log3 ($hash, 4, $name."_Define: $name $type $hash->{LEDTYPE} $iodev $hash->{SLOT}");
# Verify IODev is valid
@@ -140,41 +146,47 @@ sub MilightDevice_Define($$)
}
# Look for already defined device on IODev
- if (defined($hash->{IODev}->{$hash->{SLOT}}->{NAME}))
+ if ($hash->{SLOT} ne 'A' && defined($hash->{IODev}->{$hash->{SLOT}}->{NAME}))
{
# If defined slot does not match current device name don't allow new definition. Redefining the same device is ok though.
- return "Slot $hash->{SLOT} already defined as $hash->{IODev}->{$hash->{SLOT}}->{NAME}" if ($hash->{IODev}->{$hash->{SLOT}}->{NAME} ne $name);
+ #return "Slot $hash->{SLOT} already defined as $hash->{IODev}->{$hash->{SLOT}}->{NAME}" if ($hash->{IODev}->{$hash->{SLOT}}->{NAME} ne $name);
}
# Define device on IODev
- $hash->{IODev}->{$hash->{SLOT}}->{NAME} = $name;
+ if ($hash->{SLOT} ne 'A')
+ {
+ $hash->{IODev}->{$hash->{SLOT}}->{NAME} = $name;
+ #$hash->{IODev}->{$hash->{SLOT}}->{DEVNAME} = $name;
+ }
# Define Command Queue
my @cmdQueue = [];
$hash->{helper}->{cmdQueue} = \@cmdQueue;
- # Colormap / Commandsets
- if (($hash->{LEDTYPE} eq 'RGBW') || ($hash->{LEDTYPE} eq 'RGB'))
- {
- $hash->{helper}->{COLORMAP} = MilightDevice_ColorConverter($hash);
- }
+ my $baseCmds = "on off toggle dimup dimdown";
- my $baseCmds = "on off toggle dim:slider,0,".round(100/MilightDevice_DimSteps($hash)).",100 dimup dimdown";
my $sharedCmds = "pair unpair";
my $rgbCmds = "hsv rgb:colorpicker,RGB hue:colorpicker,HUE,0,1,360 saturation:slider,0,100,100 restorePreviousState:noArg saveState:noArg restoreState:noArg preset";
- $hash->{helper}->{COMMANDSET} = "$baseCmds discoModeUp:noArg discoSpeedUp:noArg discoSpeedDown:noArg $sharedCmds $rgbCmds"
+ $hash->{helper}->{COMMANDSET} = "$baseCmds discoModeUp:noArg discoSpeedUp:noArg discoSpeedDown:noArg night:noArg white:noArg toggleWhite:noArg $sharedCmds $rgbCmds"
if ($hash->{LEDTYPE} eq 'RGBW');
$hash->{helper}->{COMMANDSET} = "$baseCmds discoModeUp:noArg discoModeDown:noArg discoSpeedUp:noArg discoSpeedDown:noArg $sharedCmds $rgbCmds"
if ($hash->{LEDTYPE} eq 'RGB');
- $hash->{helper}->{COMMANDSET} = "$baseCmds ct:colorpicker,CT,3000,320,6500 $sharedCmds"
+ $hash->{helper}->{COMMANDSET} = "$baseCmds ct:colorpicker,CT,3000,320,6500 night:noArg $sharedCmds"
if ($hash->{LEDTYPE} eq 'White');
+ my $defaultcommandset = $hash->{helper}->{COMMANDSET};
+ $hash->{helper}->{COMMANDSET} .= " dim:slider,0,".round(100/MilightDevice_DimSteps($hash)).",100";
+
# webCmds
if (!defined($attr{$name}{webCmd}))
{
- $attr{$name}{webCmd} = 'rgb:rgb ffffff:rgb ff2a00:rgb 00ff00:rgb 0000ff:rgb ffff00:on:off:dim' if (($hash->{LEDTYPE} eq 'RGBW')|| ($hash->{LEDTYPE} eq 'RGB'));
- $attr{$name}{webCmd} = 'on:off:dim:ct' if ($hash->{LEDTYPE} eq 'White');
+ $attr{$name}{webCmd} = 'on:off:dim:hue:night:rgb ffffff:rgb ff0000:rgb 00ff00:rgb 0000ff:rgb ffff00' if ($hash->{LEDTYPE} eq 'RGBW');
+ $attr{$name}{webCmd} = 'on:off:dim:hue:rgb ffffff:rgb ff0000:rgb 00ff00:rgb 0000ff:rgb ffff00' if ($hash->{LEDTYPE} eq 'RGB');
+ $attr{$name}{webCmd} = 'on:off:dim:ct:night' if ($hash->{LEDTYPE} eq 'White');
}
+
+ $hash->{helper}->{GAMMAMAP} = MilightDevice_CreateGammaMapping($hash, 1.0);
+
# Define devStateIcon
$attr{$name}{devStateIcon} = '{(MilightDevice_devStateIcon($name),"toggle")}' if(!defined($attr{$name}{devStateIcon}));
@@ -192,9 +204,49 @@ sub MilightDevice_Define($$)
# IODev
$attr{$name}{IODev} = $hash->{IODev} if (!defined($attr{$name}{IODev}));
+ InternalTimer(gettimeofday() + 5, "MilightDevice_Init", $hash, 0);
+
return undef;
}
+sub MilightDevice_Init($)
+{
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ if( AttrVal($hash->{NAME}, "gamma", "1.0") eq "1.0")
+ {
+ Log3 $name, 5, $name." dimstep ".round(100/MilightDevice_DimSteps($hash))." / gamma 1.0";
+ } else {
+ $hash->{helper}->{COMMANDSET} =~ s/dim:slider,0,.*,100/dim:slider,0,1,100/g;
+ Log3 $name, 5, $name." dimstep 1 / gamma ".AttrVal($hash->{NAME}, "gamma", "1.0");
+ $hash->{helper}->{GAMMAMAP} = MilightDevice_CreateGammaMapping($hash, AttrVal($hash->{NAME}, "gamma", "1.0"));
+ }
+
+
+ # Colormap / Commandsets
+ if (($hash->{LEDTYPE} eq 'RGBW') || ($hash->{LEDTYPE} eq 'RGB'))
+ {
+ my @a = split(',', "0,0,0,0,0,0");
+ if ( defined($hash->{".colorCast"} ) )
+ {
+ @a = split(',', AttrVal($hash->{NAME}, "colorCast", "0,0,0,0,0,0"));
+ @a = split(',', "0,0,0,0,0,0") unless (@a == 6);
+ foreach my $tc (@a)
+ {
+ @a = split(',', "0,0,0,0,0,0") unless ($tc =~ m/^\s*[\-]{0,1}[0-9]+[\.]{0,1}[0-9]*\s*$/g);
+ @a = split(',', "0,0,0,0,0,0") if (abs($tc) >= 30);
+ }
+ }
+ $hash->{helper}->{COLORMAP} = MilightDevice_ColorConverter($hash, @a);
+
+ }
+
+
+ return undef;
+}
+
+
#####################################
# Undefine device
sub MilightDevice_Undef(@)
@@ -203,7 +255,7 @@ sub MilightDevice_Undef(@)
RemoveInternalTimer($hash);
# Remove slot on bridge
- delete ($hash->{IODev}->{$hash->{SLOT}}->{NAME});
+ delete ($hash->{IODev}->{$hash->{SLOT}}->{NAME}) if ($hash->{SLOT} ne 'A');
return undef;
}
@@ -219,44 +271,31 @@ sub MilightDevice_Set(@)
my $event = undef;
my $usage = "set $name ...";
+ if ($hash->{IODev}->{STATE} ne "ok") {
+ readingsSingleUpdate($hash, "state", "error", 1);
+ $flags = "q";
+ $args[2] .= "q" if ($args[2] !~ m/.*[qQ].*/);
+ # return SetExtensions($hash, $hash->{helper}->{COMMANDSET}, $name, $cmd, @args);
+ # IO error, we need to keep our current state settings!
+ }
# Commands that map to other commands
if ($cmd eq "toggle")
{
- $cmd = ReadingsVal($name,"state","on") eq "off" ? "on" :"off";
+ $cmd = ReadingsVal($name,"state","on") ne "off" ? "off" :"on";
+ }
+ elsif ($cmd eq "white")
+ {
+ $cmd = "saturation";
+ $args[0] = 0;
+ }
+ elsif ($cmd eq "toggleWhite")
+ {
+ $cmd = "saturation";
+ $args[0] = (ReadingsVal($name,"saturation",100) > 0) ? 0 : 100;
}
# Commands
- if ($cmd eq 'pair')
- {
- if (defined($args[0]))
- {
- return "Usage: set $name pair [seconds(0..X)(default 3)]" if ($args[0] !~ /^\d+$/);
- $ramp = $args[0];
- }
- else { $ramp = 3; } # Default pair for 3 seconds
-
- MilightDevice_CmdQueue_Clear($hash);
- return MilightDevice_RGBW_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGBW');
- return MilightDevice_White_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'White');
- return MilightDevice_RGB_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGB');
- }
-
- elsif ($cmd eq 'unpair')
- {
- if (defined($args[0]))
- {
- return "Usage: set $name unpair [seconds(0..X)(default 3)]" if ($args[0] !~ /^\d+$/);
- $ramp = $args[0];
- }
- else { $ramp = 3; } # Default unpair for 3 seconds
-
- MilightDevice_CmdQueue_Clear($hash);
- return MilightDevice_RGBW_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGBW');
- return MilightDevice_White_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'White');
- return MilightDevice_RGB_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGB');
- }
-
- elsif ($cmd eq 'on')
+ if ($cmd eq 'on')
{
if (defined($args[0]))
{
@@ -268,6 +307,7 @@ sub MilightDevice_Set(@)
$ramp = $attr{$name}{defaultRampOn};
}
return MilightDevice_RGBW_On($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_DimOn($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'White' && AttrVal($hash->{NAME}, "dimOffWhite", 0) == 1);
return MilightDevice_White_On($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'White');
return MilightDevice_RGB_On($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGB');
}
@@ -284,10 +324,125 @@ sub MilightDevice_Set(@)
$ramp = $attr{$name}{defaultRampOff};
}
return MilightDevice_RGBW_Off($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_DimOff($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'White' && AttrVal($hash->{NAME}, "dimOffWhite", 0) == 1);
return MilightDevice_White_Off($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'White');
return MilightDevice_RGB_Off($hash, $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGB');
}
+ # Set HSV value
+ elsif ($cmd eq 'hsv')
+ {
+ $usage = "Usage: set $name hsv ,, [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
+ return $usage if ($args[0] !~ /^(\d{1,3}),(\d{1,3}),(\d{1,3})$/);
+ my ($h, $s, $v) = ($1, $2, $3);
+ return "Invalid hue ($h): valid range 0..360" if !(($h >= 0) && ($h <= 360));
+ return "Invalid saturation ($s): valid range 0..100" if !(($s >= 0) && ($s <= 100));
+ return "Invalid brightness ($v): valid range 0..100" if !(($v >= 0) && ($v <= 100));
+ if (defined($args[1]))
+ {
+ return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
+ $ramp = $args[1];
+ }
+ if (defined($args[2]))
+ {
+ return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
+ $flags = $args[2];
+ }
+ return MilightDevice_HSV_Transition($hash, $h, $s, $v, $ramp, $flags);
+ }
+
+ # Dim to a fixed percentage with transition if requested
+ elsif ($cmd eq 'dim')
+ {
+ $usage = "Usage: set $name dim [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
+ return $usage if (($args[0] !~ /^\d+$/) || (!($args[0] ~~ [0..100]))); # Decimal value for percent between 0..100
+ if (defined($args[1]))
+ {
+ return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
+ $ramp = $args[1];
+ }
+ if (defined($args[2]))
+ {
+ return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
+ $flags = $args[2];
+ }
+ return MilightDevice_RGBW_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'White');
+ return MilightDevice_RGB_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGB');
+ }
+
+ # Set night mode
+ elsif ($cmd eq 'night')
+ {
+ if (defined($args[0]))
+ {
+ return "Usage: set $name night";
+ }
+ return MilightDevice_RGBW_Night($hash) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_Night($hash) if ($hash->{LEDTYPE} eq 'White');
+ }
+
+ # Set hue
+ elsif ($cmd eq 'hue')
+ {
+ $usage = "Usage: set $name hue [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
+ return $usage if (($args[0] !~ /^(\d+)$/) || (!($args[0] ~~ [0..360])));
+ if (defined($args[1]))
+ {
+ return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
+ $ramp = $args[1];
+ }
+ if (defined($args[2]))
+ {
+ return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
+ $flags = $args[2];
+ }
+ my $sat = ReadingsVal($hash->{NAME}, "saturation", 100);
+ $sat = 100 if(ReadingsVal($hash->{NAME}, "saturation", 0) == 0);
+ return MilightDevice_HSV_Transition($hash, $args[0], $sat, ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), $ramp, $flags);
+ }
+
+ # Set color temperature
+ elsif ($cmd eq 'ct')
+ {
+ if (defined($args[0]))
+ {
+ return "Usage: set $name ct <3000=Warm..6500=Cool>" if (($args[0] !~ /^\d+$/) || (!($args[0] ~~ [2500..7000])));
+ }
+ if (defined($args[1]))
+ {
+ return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
+ $ramp = $args[1];
+ }
+ if (defined($args[2]))
+ {
+ return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
+ $flags = $args[2];
+ }
+ return MilightDevice_White_SetColourTemp($hash, $args[0], $ramp, $flags);
+ }
+
+ # Set RGB value
+ elsif( $cmd eq "rgb")
+ {
+ $usage = "Usage: set $name rgb RRGGBB [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
+ return $usage if ($args[0] !~ /^([0-9A-Fa-f]{1,2})([0-9A-Fa-f]{1,2})([0-9A-Fa-f]{1,2})$/);
+ my( $r, $g, $b ) = (hex($1)/255.0, hex($2)/255.0, hex($3)/255.0);
+ my( $h, $s, $v ) = Color::rgb2hsv($r,$g,$b);
+ $h = round($h * 360); $s = round($s * 100); $v = round($v * 100);
+ if (defined($args[1]))
+ {
+ return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
+ $ramp = $args[1];
+ }
+ if (defined($args[2]))
+ {
+ return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
+ $flags = $args[2];
+ }
+ return MilightDevice_HSV_Transition($hash, $h, $s, $v, $ramp, $flags);
+ }
+
# Dim up by 1 "dimStep" or by a percentage with transition if requested
elsif ($cmd eq 'dimup')
{
@@ -350,84 +505,6 @@ sub MilightDevice_Set(@)
return MilightDevice_RGB_Dim($hash, $newBrightness, $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGB');
}
- # Dim to a fixed percentage with transition if requested
- elsif ($cmd eq 'dim')
- {
- $usage = "Usage: set $name dim [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
- return $usage if (($args[0] !~ /^\d+$/) || (!($args[0] ~~ [0..100]))); # Decimal value for percent between 0..100
- if (defined($args[1]))
- {
- return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
- $ramp = $args[1];
- }
- if (defined($args[2]))
- {
- return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
- $flags = $args[2];
- }
- return MilightDevice_RGBW_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGBW');
- return MilightDevice_White_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'White');
- return MilightDevice_RGB_Dim($hash, $args[0], $ramp, $flags) if ($hash->{LEDTYPE} eq 'RGB');
- }
-
- elsif( $cmd eq "rgb")
- {
- $usage = "Usage: set $name rgb RRGGBB [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
- return $usage if ($args[0] !~ /^([0-9A-Fa-f]{1,2})([0-9A-Fa-f]{1,2})([0-9A-Fa-f]{1,2})$/);
- my( $r, $g, $b ) = (hex($1)/255.0, hex($2)/255.0, hex($3)/255.0);
- my( $h, $s, $v ) = Color::rgb2hsv($r,$g,$b);
- $h = round($h * 360); $s = round($s * 100); $v = round($v * 100);
- if (defined($args[1]))
- {
- return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
- $ramp = $args[1];
- }
- if (defined($args[2]))
- {
- return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
- $flags = $args[2];
- }
- return MilightDevice_HSV_Transition($hash, $h, $s, $v, $ramp, $flags);
- }
-
- elsif ($cmd eq 'hsv')
- {
- $usage = "Usage: set $name hsv ,, [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
- return $usage if ($args[0] !~ /^(\d{1,3}),(\d{1,3}),(\d{1,3})$/);
- my ($h, $s, $v) = ($1, $2, $3);
- return "Invalid hue ($h): valid range 0..360" if !(($h >= 0) && ($h <= 360));
- return "Invalid saturation ($s): valid range 0..100" if !(($s >= 0) && ($s <= 100));
- return "Invalid brightness ($v): valid range 0..100" if !(($v >= 0) && ($v <= 100));
- if (defined($args[1]))
- {
- return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
- $ramp = $args[1];
- }
- if (defined($args[2]))
- {
- return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
- $flags = $args[2];
- }
- return MilightDevice_HSV_Transition($hash, $h, $s, $v, $ramp, $flags);
- }
-
- elsif ($cmd eq 'hue')
- {
- $usage = "Usage: set $name hue [seconds(0..x)] [flags(l=long path|q=don't clear queue)]";
- return $usage if (($args[0] !~ /^(\d+)$/) || (!($args[0] ~~ [0..360])));
- if (defined($args[1]))
- {
- return $usage if (($args[1] !~ /^\d+$/) && ($args[1] > 0)); # Decimal value for ramp > 0
- $ramp = $args[1];
- }
- if (defined($args[2]))
- {
- return $usage if ($args[2] !~ m/.*[lLqQ].*/); # Flags l=Long way round for transition, q=don't clear queue (add to end)
- $flags = $args[2];
- }
- return MilightDevice_HSV_Transition($hash, $args[0], ReadingsVal($hash->{NAME}, "saturation", 100), ReadingsVal($hash->{NAME}, "brightness", 100), $ramp, $flags);
- }
-
elsif ($cmd eq 'saturation')
{
$usage = "Usage: set $name saturation [seconds(0..x)] [flags(q=don't clear queue)]";
@@ -442,7 +519,7 @@ sub MilightDevice_Set(@)
return $usage if ($args[2] !~ m/.*[qQ].*/); # Flags q=don't clear queue (add to end)
$flags = $args[2];
}
- return MilightDevice_HSV_Transition($hash, ReadingsVal($hash->{NAME}, "hue", 0), $args[0], ReadingsVal($hash->{NAME}, "brightness", 100), $ramp, $flags);
+ return MilightDevice_HSV_Transition($hash, ReadingsVal($hash->{NAME}, "hue", 0), $args[0], ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), $ramp, $flags);
}
elsif ($cmd eq 'discoModeUp')
@@ -465,15 +542,6 @@ sub MilightDevice_Set(@)
return MilightDevice_RGBW_DiscoModeSpeed($hash, 0);
}
- elsif ($cmd eq 'ct')
- {
- if (defined($args[0]))
- {
- return "Usage: set $name ct <3000=Warm..6500=Cool>" if (($args[0] !~ /^\d+$/) || (!($args[0] ~~ [3000..6500])));
- }
- return MilightDevice_White_SetColourTemp($hash, $args[0]);
- }
-
elsif ($cmd eq 'restorePreviousState')
{
# Restore the previous state (as store in previous* readings)
@@ -493,6 +561,7 @@ sub MilightDevice_Set(@)
my ($h, $s, $v) = MilightDevice_HSVFromStr($hash, ReadingsVal($hash->{NAME}, "savedState", MilightDevice_HSVToStr($hash, 0, 0, 0)));
return MilightDevice_HSV_Transition($hash, $h, $s, $v, 0, '');
}
+
elsif ($cmd eq 'preset')
{
my $preset = "+";
@@ -520,6 +589,36 @@ sub MilightDevice_Set(@)
return MilightDevice_HSV_Transition($hash, $h, $s, $v, 0, '');
}
+ elsif ($cmd eq 'pair')
+ {
+ if (defined($args[0]))
+ {
+ return "Usage: set $name pair [seconds(0..X)(default 3)]" if ($args[0] !~ /^\d+$/);
+ $ramp = $args[0];
+ }
+ else { $ramp = 3; } # Default pair for 3 seconds
+
+ MilightDevice_CmdQueue_Clear($hash);
+ return MilightDevice_RGBW_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'White');
+ return MilightDevice_RGB_Pair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGB');
+ }
+
+ elsif ($cmd eq 'unpair')
+ {
+ if (defined($args[0]))
+ {
+ return "Usage: set $name unpair [seconds(0..X)(default 3)]" if ($args[0] !~ /^\d+$/);
+ $ramp = $args[0];
+ }
+ else { $ramp = 3; } # Default unpair for 3 seconds
+
+ MilightDevice_CmdQueue_Clear($hash);
+ return MilightDevice_RGBW_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_White_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'White');
+ return MilightDevice_RGB_UnPair($hash, $ramp) if ($hash->{LEDTYPE} eq 'RGB');
+ }
+
return SetExtensions($hash, $hash->{helper}->{COMMANDSET}, $name, $cmd, @args);
}
@@ -535,13 +634,13 @@ sub MilightDevice_Get(@)
my $cmd= $args[1];
if($cmd eq "rgb" || $cmd eq "RGB") {
- return ReadingsVal($name, "RGB", "FFFFFF");
+ return ReadingsVal($name, "rgb", "FFFFFF");
}
elsif($cmd eq "hsv") {
return MilightDevice_HSVToStr($hash, ReadingsVal($hash->{NAME}, "hue", 0), ReadingsVal($hash->{NAME}, "saturation", 0), ReadingsVal($hash->{NAME}, "brightness", 0));
}
- return "Unknown argument $cmd, choose one of rgb:noArg RGB:noArg hsv:noArg";
+ return "Unknown argument $cmd, choose one of rgb:noArg hsv:noArg";
}
#####################################
@@ -555,21 +654,57 @@ sub MilightDevice_Attr(@)
Log3 ($hash, 4, "$hash->{NAME}_Attr: Cmd: $cmd; Attribute: $attribName; Value: $attribVal");
+ if ($cmd eq 'set' && $attribName eq 'gamma')
+ {
+ return "gamma is required as numerical value with one decimal (eg. 0.5 or 2.2)" if ($attribVal !~ /^\d*\.\d*$/);
+ $hash->{helper}->{GAMMAMAP} = MilightDevice_CreateGammaMapping($hash, $attribVal);
+ if($attribVal ne "1.0")
+ {
+ $hash->{helper}->{COMMANDSET} =~ s/dim:slider,0,.*,100/dim:slider,0,1,100/g;
+ }
+ }
# Allows you to modify the default number of dimSteps for a device
- if ($cmd eq 'set' && $attribName eq 'dimStep')
+ elsif ($cmd eq 'set' && $attribName eq 'dimStep')
{
return "dimStep is required as numerical value [1..100]" if ($attribVal !~ /^\d*$/) || (($attribVal < 1) || ($attribVal > 100));
}
# Allows you to set a default transition time for on/off
- if ($cmd eq 'set' && (($attribName eq 'defaultRampOn') || ($attribName eq 'defaultRampOff')))
+ elsif ($cmd eq 'set' && (($attribName eq 'defaultRampOn') || ($attribName eq 'defaultRampOff')))
{
return "defaultRampOn/Off is required as numerical value [0..100]" if ($attribVal !~ /^[0-9]*\.?[0-9]*$/) || (($attribVal < 0) || ($attribVal > 100));
}
# List of presets in hsv separated by space. Loaded by set command preset X
- if ($cmd eq 'set' && ($attribName eq 'presets'))
+ elsif ($cmd eq 'set' && ($attribName eq 'presets'))
{
return "presets is required as space separated list of hsv(h,s,v) (eg. 0,0,100, 0,100,50)" if ($attribVal !~ /^[(\d{1,3}),(\d{1,3}),(\d{1,3})(?:$|\s)]*$/);
}
+ elsif ($cmd eq 'set' && $attribName eq 'colorCast')
+ {
+ return "colorCast: only works with RGB(W) devices" if ($hash->{LEDTYPE} eq 'White');
+ my @a = split(',', $attribVal);
+ my $msg = "colorCast: correction requires red, yellow, green ,cyan, blue, magenta (each in a range of -29 .. 29)";
+ return $msg unless (@a == 6);
+ foreach my $tc (@a)
+ {
+ return $msg unless ($tc =~ m/^\s*[\-]{0,1}[0-9]+[\.]{0,1}[0-9]*\s*$/g);
+ return $msg if (abs($tc) >= 30);
+ }
+ $hash->{helper}->{COLORMAP} = MilightDevice_ColorConverter($hash, @a);
+
+ #MilightDevice_RGB_ColorConverter($hash, @a);
+ if ($init_done && !(@{$hash->{helper}->{cmdQueue}} > 0))
+ {
+ my $hue = $hash->{READINGS}->{hue}->{VAL};
+ my $sat = $hash->{READINGS}->{saturation}->{VAL};
+ my $val = $hash->{READINGS}->{brightness}->{VAL};
+ return MilightDevice_RGBW_SetHSV($hash, $hue, $sat, $val, 1) if ($hash->{LEDTYPE} eq 'RGBW');
+ return MilightDevice_RGB_SetHSV($hash, $hue, $sat, $val, 1) if ($hash->{LEDTYPE} eq 'RGB');
+ }
+ }
+ elsif ($cmd eq 'set' && $attribName eq 'defaultBrightness')
+ {
+ return "defaultBrighness: has to be between ".round(100/MilightDevice_DimSteps($hash))." and 100" unless ($attribVal ~~ [round(100/MilightDevice_DimSteps($hash))..100]);
+ }
return undef;
}
@@ -590,7 +725,7 @@ sub MilightDevice_Notify(@)
# Clear inProgress flag
readingsSingleUpdate($hash, "transitionInProgress", 0, 1);
-
+
# Restore previous state (as defined in statefile)
# wait for global: INITIALIZED after start up
if (@{$events}[0] eq 'INITIALIZED')
@@ -650,22 +785,23 @@ sub MilightDevice_RGB_UnPair(@)
sub MilightDevice_RGB_On(@)
{
my ($hash, $ramp, $flags) = @_;
- my $v = 100;
+ my $name = $hash->{NAME};
+ my $v = AttrVal($hash->{NAME}, "defaultBrightness", 36);
Log3 ($hash, 4, "$hash->{NAME}_RGB_On: RGB slot $hash->{SLOT} set on $ramp");
# Switch on with same brightness it was switched off with, or max if undefined.
if (ReadingsVal($hash->{NAME}, "state", "off") eq "off")
{
- $v = ReadingsVal($hash->{NAME}, "brightness_on", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness_on", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
else
{
- $v = ReadingsVal($hash->{NAME}, "brightness", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
# When turning on, make sure we request at least minimum dim step.
if ($v < round(100/MilightDevice_DimSteps($hash)))
{
- $v = 100;
+ $v = round(100/MilightDevice_DimSteps($hash));
}
return MilightDevice_RGB_Dim($hash, $v, $ramp, $flags);
@@ -675,14 +811,17 @@ sub MilightDevice_RGB_On(@)
sub MilightDevice_RGB_Off(@)
{
my ($hash, $ramp, $flags) = @_;
+ my $name = $hash->{NAME};
Log3 ($hash, 4, "$hash->{NAME}_RGB_Off: RGB slot $hash->{SLOT} set off $ramp");
# Store value of brightness before turning off
# "on" will be of the form "on 50" where 50 is current dimlevel
if (ReadingsVal($hash->{NAME}, "state", "off") ne "off")
{
- readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", 100), 1);
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+
# Dim down to min brightness then send off command (avoid flicker on turn on)
- MilightDevice_RGB_Dim($hash, 100/MilightDevice_DimSteps($hash), $ramp, $flags);
+ MilightDevice_RGB_Dim($hash, round(100/MilightDevice_DimSteps($hash)), $ramp, $flags);
return MilightDevice_RGB_Dim($hash, 0, 0, 'q');
}
else
@@ -709,8 +848,12 @@ sub MilightDevice_RGB_SetHSV(@)
Log3 ($hash, 4, "$hash->{NAME}_RGB_setHSV: RGB slot $hash->{SLOT} set h:$hue, s:$sat, v:$val");
$sat = 100;
MilightDevice_SetHSV_Readings($hash, $hue, $sat, $val);
+
+ # apply gamma correction
+ my $gammaVal = $hash->{helper}->{GAMMAMAP}[$val];
+
# convert to device specs
- my ($cv, $cl, $wl) = MilightDevice_RGB_ColorConverter($hash, $hue, $sat, $val);
+ my ($cv, $cl, $wl) = MilightDevice_RGB_ColorConverter($hash, $hue, $sat, $gammaVal);
Log3 ($hash, 4, "$hash->{NAME}_RGB_setHSV: RGB slot $hash->{SLOT} set levels: $cv, $cl, $wl");
$repeat = 1 if (!defined($repeat));
@@ -765,10 +908,11 @@ sub MilightDevice_RGB_SetHSV(@)
sub MilightDevice_RGB_ColorConverter(@)
{
my ($hash, $h, $s, $v) = @_;
+
my $color = $hash->{helper}->{COLORMAP}[$h % 360];
# there are 0..9 dim level, setup correction
- my $valueSpread = 100/MilightDevice_DimSteps($hash);
+ my $valueSpread = round(100/MilightDevice_DimSteps($hash));
my $totalVal = round($v / $valueSpread);
# saturation 100..50: color full, white increase. 50..0 white full, color decrease
my $colorVal = ($s >= 50) ? $totalVal : int(($s / 50 * $totalVal) +0.5);
@@ -786,7 +930,7 @@ sub MilightDevice_RGBW_Pair(@)
$numSeconds = 3 if (($numSeconds || 0) == 0);
Log3 ($hash, 4, "$hash->{NAME}_RGBW_Pair: $hash->{LEDTYPE} at $hash->{CONNECTION}, slot $hash->{SLOT}: pair $numSeconds");
# find my slot and get my group-all-on cmd
- my $ctrl = @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd;
+ my $ctrl = @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd;
# Send on command once a second
for (my $i = 0; $i < $numSeconds; $i++)
{
@@ -802,7 +946,7 @@ sub MilightDevice_RGBW_UnPair(@)
$numSeconds = 3 if (($numSeconds || 0) == 0);
Log3 ($hash, 4, "$hash->{NAME}_RGBW_UnPair: $hash->{LEDTYPE} at $hash->{CONNECTION}, slot $hash->{SLOT}: unpair $numSeconds");
# find my slot and get my group-all-on cmd
- my $ctrl = @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd;
+ my $ctrl = @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd;
# Send on command every 200ms
for (my $i = 0; $i < $numSeconds; $i++)
@@ -820,21 +964,22 @@ sub MilightDevice_RGBW_UnPair(@)
sub MilightDevice_RGBW_On(@)
{
my ($hash, $ramp, $flags) = @_;
- my $v = 100;
+ my $name = $hash->{NAME};
+ my $v = AttrVal($hash->{NAME}, "defaultBrightness", 36);
Log3 ($hash, 4, "$hash->{NAME}_RGBW_On: Set ON; Ramp: $ramp");
# Switch on with same brightness it was switched off with, or max if undefined.
- if (ReadingsVal($hash->{NAME}, "state", "off") eq "off")
+ if (ReadingsVal($hash->{NAME}, "state", "off") eq "off" || ReadingsVal($hash->{NAME}, "state", "off") eq "night")
{
- $v = ReadingsVal($hash->{NAME}, "brightness_on", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness_on", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
else
{
- $v = ReadingsVal($hash->{NAME}, "brightness", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
# When turning on, make sure we request at least minimum dim step.
if ($v < round(100/MilightDevice_DimSteps($hash)))
{
- $v = 100;
+ $v = round(100/MilightDevice_DimSteps($hash));
}
return MilightDevice_RGBW_Dim($hash, $v, $ramp, $flags);
@@ -844,14 +989,17 @@ sub MilightDevice_RGBW_On(@)
sub MilightDevice_RGBW_Off(@)
{
my ($hash, $ramp, $flags) = @_;
+ my $name = $hash->{NAME};
Log3 ($hash, 4, "$hash->{NAME}_RGBW_Off: Set OFF; Ramp: $ramp");
# Store value of brightness before turning off
# "on" will be of the form "on 50" where 50 is current dimlevel
- if (ReadingsVal($hash->{NAME}, "state", "off") ne "off")
+ if (ReadingsVal($hash->{NAME}, "state", "off") ne "off" && ReadingsVal($hash->{NAME}, "state", "off") ne "night")
{
- readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", 100), 1);
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", 0), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+
# Dim down to min brightness then send off command (avoid flicker on turn on)
- MilightDevice_RGBW_Dim($hash, 100/MilightDevice_DimSteps($hash), $ramp, $flags);
+ MilightDevice_RGBW_Dim($hash, round(100/MilightDevice_DimSteps($hash)), $ramp, $flags);
return MilightDevice_RGBW_Dim($hash, 0, 0, 'q');
}
else
@@ -861,6 +1009,26 @@ sub MilightDevice_RGBW_Off(@)
}
}
+#####################################
+sub MilightDevice_RGBW_Night(@)
+{
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+ Log3 ($hash, 4, "$hash->{NAME}_RGBW_Night: Set NIGHTMODE");
+ if(ReadingsVal($hash->{NAME}, "state", "off") ne "night") {
+ if (ReadingsVal($hash->{NAME}, "brightness", 0) > 0)
+ {
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", 4), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ }
+ IOWrite($hash, @RGBWCmdsOff[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd); # off
+ }
+ IOWrite($hash, @RGBWCmdsNt[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd); # night
+ readingsSingleUpdate($hash, "state", "night", 1);
+ MilightDevice_BridgeDevices_Update($hash, "state") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ return undef;
+}
+
#####################################
sub MilightDevice_RGBW_Dim(@)
{
@@ -881,9 +1049,12 @@ sub MilightDevice_RGBW_SetHSV(@)
my $cv = $hash->{helper}->{COLORMAP}[$hue % 360];
+ # apply gamma correction
+ my $gammaVal = $hash->{helper}->{GAMMAMAP}[$val];
+
# brightness 2..27 (x02..x1b) | 25 dim levels
- my $cf = round((($val / 100) * MilightDevice_DimSteps($hash)) + 2);
+ my $cf = round((($gammaVal / 100) * MilightDevice_DimSteps($hash)) + 1);
if ($sat < 20)
{
$wl = $cf;
@@ -903,11 +1074,11 @@ sub MilightDevice_RGBW_SetHSV(@)
# NOTE: All commands sent twice for reliability (it's udp with no feedback)
- # Off is shifted to "2" above so check for < 3
- if (($wl < 3) && ($cl < 3)) # off
+ # Off is shifted to "2" above so check for < 2
+ if (($wl < 2) && ($cl < 2)) # off
{
- IOWrite($hash, @RGBWCmdsOff[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd); # group off
- IOWrite($hash, @RGBWCmdsOff[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if ($repeat eq 1); # group off
+ IOWrite($hash, @RGBWCmdsOff[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd); # group off
+ IOWrite($hash, @RGBWCmdsOff[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if ($repeat eq 1); # group off
$hash->{helper}->{whiteLevel} = 0;
$hash->{helper}->{colorLevel} = 0;
}
@@ -915,22 +1086,22 @@ sub MilightDevice_RGBW_SetHSV(@)
{
if ($wl > 0) # white
{
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
- IOWrite($hash, @RGBWCmdsWT[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd); # white
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
+ IOWrite($hash, @RGBWCmdsWT[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd); # white
IOWrite($hash, $RGBWCmdBri.chr($wl).$RGBWCmdEnd); # brightness
if ($repeat eq 1) {
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
- IOWrite($hash, @RGBWCmdsWT[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd); # white
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
+ IOWrite($hash, @RGBWCmdsWT[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd); # white
IOWrite($hash, $RGBWCmdBri.chr($wl).$RGBWCmdEnd); # brightness
}
}
elsif ($cl > 0) # color
{
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
IOWrite($hash, $RGBWCmdCol.chr($cv).$RGBWCmdEnd); # color
IOWrite($hash, $RGBWCmdBri.chr($cl).$RGBWCmdEnd); # brightness
if ($repeat eq 1) {
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($wl > 0) || ($cl > 0)); # group on
IOWrite($hash, $RGBWCmdCol.chr($cv).$RGBWCmdEnd); # color
IOWrite($hash, $RGBWCmdBri.chr($cl).$RGBWCmdEnd); # brightness
}
@@ -959,7 +1130,7 @@ sub MilightDevice_RGBW_DiscoModeStep(@)
MilightDevice_SetDisco_Readings($hash, $step, ReadingsVal($hash->{NAME}, 'discoSpeed', 5));
# NOTE: Only sending commands once, because it makes changes on each successive command
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($hash->{LEDTYPE} eq 'RGBW')); # group on
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($hash->{LEDTYPE} eq 'RGBW')); # group on
IOWrite($hash, "\x22\x00\x55") if (($hash->{LEDTYPE} eq 'RGB')); # switch on
if ($step == 1)
@@ -991,7 +1162,7 @@ sub MilightDevice_RGBW_DiscoModeSpeed(@)
MilightDevice_SetDisco_Readings($hash, ReadingsVal($hash->{NAME}, 'discoMode', 1), $speed);
# NOTE: Only sending commands once, because it makes changes on each successive command
- IOWrite($hash, @RGBWCmdsOn[$hash->{SLOT} -5]."\x00".$RGBWCmdEnd) if (($hash->{LEDTYPE} eq 'RGBW')); # group on
+ IOWrite($hash, @RGBWCmdsOn[$hash->{SLOTID} -5]."\x00".$RGBWCmdEnd) if (($hash->{LEDTYPE} eq 'RGBW')); # group on
IOWrite($hash, "\x22\x00\x55") if (($hash->{LEDTYPE} eq 'RGB')); # switch on
if ($speed == 1)
@@ -1018,7 +1189,7 @@ sub MilightDevice_White_Pair(@)
Log3 ($hash, 4, "$hash->{NAME}_White_Pair: $hash->{LEDTYPE} at $hash->{CONNECTION}, slot $hash->{SLOT}: pair $numSeconds");
# find my slot and get my group-all-on cmd
- my $ctrl = @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd;
+ my $ctrl = @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd;
# Send on command once a second
for (my $i = 0; $i < $numSeconds; $i++)
@@ -1036,7 +1207,7 @@ sub MilightDevice_White_UnPair(@)
Log3 ($hash, 4, "$hash->{NAME}_White_UnPair: $hash->{LEDTYPE} at $hash->{CONNECTION}, slot $hash->{SLOT}: unpair $numSeconds");
# find my slot and get my group-all-on cmd
- my $ctrl = @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd;
+ my $ctrl = @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd;
for (my $i = 0; $i < $numSeconds; $i++)
{
@@ -1053,21 +1224,22 @@ sub MilightDevice_White_UnPair(@)
sub MilightDevice_White_On(@)
{
my ($hash, $ramp, $flags) = @_;
- my $v = 100;
+ my $name = $hash->{NAME};
+ my $v = AttrVal($hash->{NAME}, "defaultBrightness", 36);
Log3 ($hash, 4, "$hash->{NAME}_White_On: Set ON: Ramp: $ramp");
# Switch on with same brightness it was switched off with, or max if undefined.
- if (ReadingsVal($hash->{NAME}, "state", "off") eq "off")
+ if (ReadingsVal($hash->{NAME}, "state", "off") eq "off" || ReadingsVal($hash->{NAME}, "state", "off") eq "night")
{
- $v = ReadingsVal($hash->{NAME}, "brightness_on", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness_on", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
else
{
- $v = ReadingsVal($hash->{NAME}, "brightness", 100);
+ $v = ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36));
}
# When turning on, make sure we request at least minimum dim step.
if ($v < round(100/MilightDevice_DimSteps($hash)))
{
- $v = 100;
+ $v = round(100/MilightDevice_DimSteps($hash));
}
return MilightDevice_White_Dim($hash, $v, $ramp, $flags);
}
@@ -1076,14 +1248,19 @@ sub MilightDevice_White_On(@)
sub MilightDevice_White_Off(@)
{
my ($hash, $ramp, $flags) = @_;
+ my $name = $hash->{NAME};
Log3 ($hash, 4, "$hash->{NAME}_White_Off: Set OFF; Ramp: $ramp");
# Store value of brightness before turning off
# "on" will be of the form "on 50" where 50 is current dimlevel
- if (ReadingsVal($hash->{NAME}, "state", "off") ne "off")
+ if (ReadingsVal($hash->{NAME}, "state", "off") ne "off" && ReadingsVal($hash->{NAME}, "state", "off") ne "night")
{
- readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", 100), 1);
+ if (ReadingsVal($hash->{NAME}, "brightness", 0) > 0)
+ {
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ }
# Dim down to min brightness then send off command (avoid flicker on turn on)
- MilightDevice_White_Dim($hash, 100/MilightDevice_DimSteps($hash), $ramp, $flags);
+ MilightDevice_White_Dim($hash, round(100/MilightDevice_DimSteps($hash)), $ramp, $flags);
return MilightDevice_White_Dim($hash, 0, 0, 'q');
}
else
@@ -1093,6 +1270,81 @@ sub MilightDevice_White_Off(@)
}
}
+#####################################
+sub MilightDevice_White_DimOff(@)
+{
+ my ($hash, $ramp, $flags) = @_;
+ my $name = $hash->{NAME};
+ Log3 ($hash, 4, "$hash->{NAME}_White_DimOff: Set OFF; Ramp: $ramp");
+
+ if (ReadingsVal($hash->{NAME}, "brightness", 0) > 0)
+ {
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ }
+
+ for (my $i = 0; $i < 12; $i++)
+ {
+ IOWrite($hash, @WhiteCmdBriDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ }
+ IOWrite($hash, @WhiteCmdsOff[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ return MilightDevice_White_Dim($hash, 0, 0, 'q');
+}
+
+
+#####################################
+sub MilightDevice_White_DimOn(@)
+{
+ my ($hash, $ramp, $flags) = @_;
+ my $name = $hash->{NAME};
+ Log3 ($hash, 4, "$hash->{NAME}_White_DimOn: Set ON; Ramp: $ramp");
+ my $v = AttrVal($hash->{NAME}, "defaultBrightness", 36);
+
+ if (ReadingsVal($hash->{NAME}, "state", "off") eq "off" || ReadingsVal($hash->{NAME}, "state", "off") eq "night")
+ {
+ $v = ReadingsVal($hash->{NAME}, "brightness_on", AttrVal($hash->{NAME}, "defaultBrightness", 36));
+ }
+ else
+ {
+ $v = ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36));
+ }
+ # When turning on, make sure we request at least minimum dim step.
+ if ($v < round(100/MilightDevice_DimSteps($hash)))
+ {
+ $v = round(100/MilightDevice_DimSteps($hash));
+ }
+
+ MilightDevice_White_Dim($hash, $v, $ramp, $flags);
+ for (my $i = 0; $i < ($v/(100/MilightDevice_DimSteps($hash))); $i++)
+ {
+ #IOWrite($hash, @WhiteCmdBriUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ }
+ #$ctrl = @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd;
+ #MilightDevice_CmdQueue_Add($hash, undef, undef, undef, $ctrl, 200, undef);
+ #return MilightDevice_White_Dim($hash, 0, 0, 'q');
+}
+
+#####################################
+sub MilightDevice_White_Night(@)
+{
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+ Log3 ($hash, 4, "$hash->{NAME}_White_NIGHT: Set NIGHTMODE");
+ if(ReadingsVal($hash->{NAME}, "state", "off") ne "night")
+ {
+ if (ReadingsVal($hash->{NAME}, "brightness", 0) > 0)
+ {
+ readingsSingleUpdate($hash, "brightness_on", ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36)), 1);
+ MilightDevice_BridgeDevices_Update($hash, "brightness_on") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ }
+ IOWrite($hash, @WhiteCmdsOff[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # off
+ }
+ IOWrite($hash, @WhiteCmdsNt[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # night
+ readingsSingleUpdate($hash, "state", "night", 1);
+ MilightDevice_BridgeDevices_Update($hash, "state") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
+ return undef;
+}
+
#####################################
sub MilightDevice_White_Dim(@)
{
@@ -1106,16 +1358,21 @@ sub MilightDevice_White_Dim(@)
sub MilightDevice_White_SetHSV(@)
{
my ($hash, $hue, $sat, $val, $repeat) = @_;
+ my $name = $hash->{NAME};
$repeat = 1 if (!defined($repeat));
+
# Validate brightness
$val = 100 if ($val > 100);
$val = 0 if ($val < 0);
+
+ # apply gamma correction
+ my $gammaVal = $hash->{helper}->{GAMMAMAP}[$val];
# Calculate brightness hardware value (11 steps for white)
my $maxWl = (100 / MilightDevice_DimSteps($hash));
- my $wl = round($val / $maxWl);
+ my $wl = round($gammaVal / $maxWl);
# On first load, whiteLevel won't be defined, define it.
$hash->{helper}->{whiteLevel} = $wl if (!defined($hash->{helper}->{whiteLevel}));
@@ -1132,18 +1389,18 @@ sub MilightDevice_White_SetHSV(@)
# Make sure we actually send off command if we should be off
if ($wl == 0)
{
- IOWrite($hash, @WhiteCmdsOff[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group off
- IOWrite($hash, @WhiteCmdsOff[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd) if ($repeat eq 1); # group off
+ IOWrite($hash, @WhiteCmdsOff[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group off
+ IOWrite($hash, @WhiteCmdsOff[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd) if ($repeat eq 1); # group off
Log3 ($hash, 4, "$hash->{NAME}_White_setHSV: OFF");
}
elsif ($wl == $maxWl)
{
- IOWrite($hash, @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on
- IOWrite($hash, @WhiteCmdsOnFull[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on full
+ IOWrite($hash, @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on
+ IOWrite($hash, @WhiteCmdsOnFull[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on full
if ($repeat eq 1) {
- IOWrite($hash, @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on
- IOWrite($hash, @WhiteCmdsOnFull[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on full
+ IOWrite($hash, @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on
+ IOWrite($hash, @WhiteCmdsOnFull[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on full
}
Log3 ($hash, 4, "$hash->{NAME}_White_setHSV: Full Brightness");
}
@@ -1151,8 +1408,8 @@ sub MilightDevice_White_SetHSV(@)
else
{
# Not off or MAX brightness, so make sure we are on
- IOWrite($hash, @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on
- IOWrite($hash, @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd) if ($repeat eq 1); # group on
+ IOWrite($hash, @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on
+ IOWrite($hash, @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd) if ($repeat eq 1); # group on
if ($hash->{helper}->{whiteLevel} > $wl)
{
@@ -1160,7 +1417,7 @@ sub MilightDevice_White_SetHSV(@)
Log3 ($hash, 4, "$hash->{NAME}_White_setHSV: Brightness decrease from $hash->{helper}->{whiteLevel} to $wl");
for (my $i=$hash->{helper}->{whiteLevel}; $i > $wl; $i--)
{
- IOWrite($hash, $WhiteCmdBriDn."\x00".$WhiteCmdEnd); # brightness down
+ IOWrite($hash, @WhiteCmdBriDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # brightness down
$hash->{helper}->{whiteLevel} = $i - 1;
}
}
@@ -1172,7 +1429,7 @@ sub MilightDevice_White_SetHSV(@)
Log3 ($hash, 4, "$hash->{NAME}_White_setHSV: Brightness increase from $hash->{helper}->{whiteLevel} to $wl");
for (my $i=$hash->{helper}->{whiteLevel}; $i < $wl; $i++)
{
- IOWrite($hash, $WhiteCmdBriUp."\x00".$WhiteCmdEnd); # brightness up
+ IOWrite($hash, @WhiteCmdBriUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # brightness up
$hash->{helper}->{whiteLevel} = $i + 1;
}
}
@@ -1193,13 +1450,14 @@ sub MilightDevice_White_SetColourTemp(@)
{
# $hue is colourTemperature (1-10), $val is brightness (0-100%)
my ($hash, $hue) = @_;
+ my $name = $hash->{NAME};
MilightDevice_CmdQueue_Clear($hash);
# Save old value of ct
my $oldHue = MilightDevice_White_ct_hwValue($hash, ReadingsVal($hash->{NAME}, "ct", 1));
# Store new values for colourTemperature and Brightness
- MilightDevice_SetHSV_Readings($hash, $hue, 0, ReadingsVal($hash->{NAME}, "brightness", 100));
+ MilightDevice_SetHSV_Readings($hash, $hue, 0, ReadingsVal($hash->{NAME}, "brightness", AttrVal($hash->{NAME}, "defaultBrightness", 36) ) );
# Validate colourTemperature (11 steps)
# 3000-6500 (350 per step) Warm-White to Cool White
# Maps backwards 1=6500 11=3000
@@ -1210,13 +1468,13 @@ sub MilightDevice_White_SetColourTemp(@)
# Set colour temperature
if ($oldHue != $hue)
{
- IOWrite($hash, @WhiteCmdsOn[$hash->{SLOT} -1]."\x00".$WhiteCmdEnd); # group on
+ IOWrite($hash, @WhiteCmdsOn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # group on
if ($oldHue > $hue)
{
Log3 ($hash, 4, "$hash->{NAME}_setColourTemp: Decrease from $oldHue to $hue");
for (my $i=$oldHue; $i > $hue; $i--)
{
- IOWrite($hash, $WhiteCmdColDn."\x00".$WhiteCmdEnd); # Cooler (colourtemp down)
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # Cooler (colourtemp up)
}
}
elsif ($oldHue < $hue)
@@ -1224,10 +1482,30 @@ sub MilightDevice_White_SetColourTemp(@)
Log3 ($hash, 4, "$hash->{NAME}_setColourTemp: Increase from $oldHue to $hue");
for (my $i=$oldHue; $i < $hue; $i++)
{
- IOWrite($hash, $WhiteCmdColUp."\x00".$WhiteCmdEnd); # Warmer (colourtemp up)
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd); # Warmer (colourtemp down)
}
}
- }
+ }
+
+ if(AttrVal($hash->{NAME}, "dimOffWhite", 0) == 1)
+ {
+ if($hue == 1)
+ {
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColDn[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ }
+ elsif($hue == 11)
+ {
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ IOWrite($hash, @WhiteCmdColUp[$hash->{SLOTID} -1]."\x00".$WhiteCmdEnd);
+ }
+ }
return undef;
}
@@ -1238,18 +1516,17 @@ sub MilightDevice_White_ct_hwValue(@)
# Couldn't get switch statement to work so using if
- if ((3000 <= $ct) && ($ct < 3320)) { return 11; }
- elsif ((3320 <= $ct) && ($ct <= 3640)) { return 10; }
- elsif ((3640 <= $ct) && ($ct < 3960)) { return 9; }
- elsif ((3960 <= $ct) && ($ct < 4280)) { return 8; }
- elsif ((4280 <= $ct) && ($ct < 4600)) { return 7; }
- elsif ((4600 <= $ct) && ($ct < 4920)) { return 6; }
- elsif ((4920 <= $ct) && ($ct < 5240)) { return 5; }
- elsif ((5240 <= $ct) && ($ct < 5560)) { return 4; }
- elsif ((5560 <= $ct) && ($ct < 5880)) { return 3; }
- elsif ((5880 <= $ct) && ($ct < 6200)) { return 2; }
- elsif ((6200 <= $ct) && ($ct <= 6500)) { return 1; }
- else { return 1; }
+ if ($ct < 3320) { return 11; }
+ elsif ($ct < 3640) { return 10; }
+ elsif ($ct < 3960) { return 9; }
+ elsif ($ct < 4280) { return 8; }
+ elsif ($ct < 4600) { return 7; }
+ elsif ($ct < 4920) { return 6; }
+ elsif ($ct < 5240) { return 5; }
+ elsif ($ct < 5560) { return 4; }
+ elsif ($ct < 5880) { return 3; }
+ elsif ($ct < 6200) { return 2; }
+ return 1;
}
###############################################################################
@@ -1341,11 +1618,6 @@ sub MilightDevice_HSV_Transition(@)
my ($hash, $hue, $sat, $val, $ramp, $flags) = @_;
my ($hueFrom, $satFrom, $valFrom, $timeFrom);
- # Store target vales
- $hash->{helper}->{targetHue} = $hue;
- $hash->{helper}->{targetSat} = $sat;
- $hash->{helper}->{targetVal} = $val;
-
# Clear command queue if flag "q" not specified
MilightDevice_CmdQueue_Clear($hash) if ($flags !~ m/.*[qQ].*/);
@@ -1370,6 +1642,11 @@ sub MilightDevice_HSV_Transition(@)
Log3 ($hash, 4, "$hash->{NAME}_HSV_Transition: Current: $hueFrom,$satFrom,$valFrom");
Log3 ($hash, 4, "$hash->{NAME}_HSV_Transition: Set: $hue,$sat,$val; Ramp: $ramp; Flags: ". $flags);
+ # Store target vales
+ $hash->{helper}->{targetHue} = $hue;
+ $hash->{helper}->{targetSat} = $sat;
+ $hash->{helper}->{targetVal} = $val;
+
# if there is no ramp we don't need transition
if (($ramp || 0) == 0)
{
@@ -1469,6 +1746,7 @@ sub MilightDevice_HSV_Transition(@)
sub MilightDevice_SetHSV_Readings(@)
{
my ($hash, $hue, $sat, $val, $val_on) = @_;
+ my $name = $hash->{NAME};
readingsBeginUpdate($hash); # Start update readings
@@ -1495,7 +1773,7 @@ sub MilightDevice_SetHSV_Readings(@)
my ($r,$g,$b) = Color::hsv2rgb($hue/360.0,$sat/100.0,$val/100.0);
$r *=255; $g *=255; $b*=255;
# Store values
- readingsBulkUpdate($hash, "RGB", sprintf("%02X%02X%02X",$r,$g,$b)); # Int to Hex convert
+ readingsBulkUpdate($hash, "rgb", sprintf("%02X%02X%02X",$r,$g,$b)); # Int to Hex convert
readingsBulkUpdate($hash, "discoMode", 0);
readingsBulkUpdate($hash, "discoSpeed", 0);
}
@@ -1503,9 +1781,10 @@ sub MilightDevice_SetHSV_Readings(@)
{
readingsBulkUpdate($hash, "ct", $hue);
}
- readingsBulkUpdate($hash, "state", "on $val") if ($val > 0);
- readingsBulkUpdate($hash, "state", "off") if ($val == 0);
+ readingsBulkUpdate($hash, "state", "on $val") if ($val > 1);
+ readingsBulkUpdate($hash, "state", "off") if ($val < 2);
readingsEndUpdate($hash, 1);
+ MilightDevice_BridgeDevices_Update($hash, "bulk") if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1);
}
#####################################
@@ -1513,6 +1792,7 @@ sub MilightDevice_SetDisco_Readings(@)
{
# Step/Speed can be "1" or "0" when active
my ($hash, $step, $speed) = @_;
+ my $name = $hash->{NAME};
if (($hash->{LEDTYPE} eq 'RGBW') || ($hash->{LEDTYPE} eq 'RGB'))
{
@@ -1527,6 +1807,11 @@ sub MilightDevice_SetDisco_Readings(@)
readingsBulkUpdate($hash, "discoMode", $step);
readingsBulkUpdate($hash, "discoSpeed", $speed);
readingsEndUpdate($hash, 1);
+ if ($hash->{SLOT} eq 'A' && AttrVal($hash->{NAME}, "updateGroupDevices", 0) == 1)
+ {
+ MilightDevice_BridgeDevices_Update($hash, "discoMode");
+ MilightDevice_BridgeDevices_Update($hash, "discoSpeed");
+ }
}
}
@@ -1534,16 +1819,16 @@ sub MilightDevice_SetDisco_Readings(@)
#####################################
sub MilightDevice_ColorConverter(@)
{
- my ($hash) = @_;
+ my ($hash, $cr, $cy, $cg, $cc, $cb, $cm) = @_;
my @colorMap;
- my $adjRed = 0;
- my $adjYellow = 60;
- my $adjGreen = 120;
- my $adjCyan = 180;
- my $adjBlue = 240;
- my $adjLilac = 300;
+ my $adjRed = 0 + $cr;
+ my $adjYellow = 60 + $cy;
+ my $adjGreen = 120 + $cg;
+ my $adjCyan = 180 + $cc;
+ my $adjBlue = 240 + $cb;
+ my $adjLilac = 300 + $cm;
my $devRed = 176; # (0xB0)
#my $devYellow = 128; # (0x80)
@@ -1609,6 +1894,30 @@ sub MilightDevice_ColorConverter(@)
return \@colorMap;
}
+
+#####################################
+sub MilightDevice_CreateGammaMapping(@)
+{
+ my ($hash, $gamma) = @_;
+
+ #original wifilight gamma was inverted
+ $gamma = 1/$gamma;
+
+ my @gammaMap;
+
+ $gammaMap[0] = 0;
+ for (my $i = 1; $i <= 100; $i += 1)
+ {
+ my $correction = ($i / 100) ** (1 / $gamma);
+ $gammaMap[$i] = $correction * 100;
+ $gammaMap[$i] = round(100/MilightDevice_DimSteps($hash)) if($gammaMap[$i] < round(100/MilightDevice_DimSteps($hash)));
+ Log3 ($hash, 5, "$hash->{NAME} create gammamap v-in: ".$i.", v-out: $gammaMap[$i]");
+ }
+
+ return \@gammaMap;
+}
+
+
###############################################################################
# Device Command Queue
# Triggers commands for long running transitions for a device
@@ -1645,6 +1954,12 @@ sub MilightDevice_CmdQueue_Add(@)
sub MilightDevice_CmdQueue_Exec(@)
{
my ($hash) = @_;
+
+ if ($hash->{IODev}->{STATE} ne "ok") {
+ InternalTimer(gettimeofday() + 60, "MilightDevice_CmdQueue_Exec", $hash, 0);
+ return undef;
+ }
+
my $actualCmd = @{$hash->{helper}->{cmdQueue}}[0];
# transmission complete, remove
@@ -1700,6 +2015,11 @@ sub MilightDevice_CmdQueue_Exec(@)
sub MilightDevice_CmdQueue_Clear(@)
{
my ($hash) = @_;
+
+ if ($hash->{IODev}->{STATE} ne "ok") {
+ InternalTimer(gettimeofday() + 60, "MilightDevice_CmdQueue_Exec", $hash, 0);
+ return undef;
+ }
Log3 ($hash, 4, "$hash->{NAME}_CmdQueue_Clear");
@@ -1718,6 +2038,49 @@ sub MilightDevice_CmdQueue_Clear(@)
return undef;
}
+#####################################
+sub MilightDevice_BridgeDevices_Update(@)
+{
+ my ($hash, $attr) = @_;
+
+ my @rdlist = ($attr);
+
+ if($attr eq 'bulk')
+ {
+ @rdlist = ("state","brightness","brightness_on","hue", "saturation", "hsv", "rgb", "discoMode", "discoSpeed")if ($hash->{LEDTYPE} eq 'RGBW');
+ @rdlist = ("state","brightness","brightness_on","ct")if ($hash->{LEDTYPE} eq 'White');
+ }
+
+ my $sl = 5;
+ $sl = 1 if ($hash->{LEDTYPE} eq 'White');
+
+ for (my $i = 0; $i < 4; $i++)
+ {
+
+ my $devname = $hash->{IODev}->{$sl+$i}->{NAME};
+ next if (!defined($defs{$devname}));
+ my $device = $defs{$devname};
+
+ readingsSingleUpdate($device, "transitionInProgress", 1, 1);
+
+
+ readingsBeginUpdate($device);
+
+ foreach my $rdname (@rdlist)
+ {
+ if (exists ($device->{READINGS}{$rdname}))
+ {
+ readingsBulkUpdate($device, $rdname, $hash->{READINGS}{$rdname}{VAL}, 1);
+ Log3 ($hash, 4, $rdname.": ".$device->{READINGS}{$rdname}{VAL}." for ".$devname);
+ }
+ }
+ readingsEndUpdate($device, 1);
+ readingsSingleUpdate($device, "transitionInProgress", 0, 1);
+ }
+
+ return undef;
+}
+
1;
=pod
@@ -1738,14 +2101,14 @@ sub MilightDevice_CmdQueue_Clear(@)
Specifies the Milight device.
<devType> One of RGB, RGBW, White depending on your device.
<IODev> The MilightBridge which the device is paired with.
- <slot> The slot on the MilightBridge that the device is paired with.
+ <slot> The slot on the MilightBridge that the device is paired with or 'A' to group all slots.
Readings
-
state
- [on xxx|off]: Current state of the device (xxx = 0-100%).
+ [on xxx|off|night]: Current state of the device / night mode (xxx = 0-100%).
-
brightness
@@ -1756,7 +2119,7 @@ sub MilightDevice_CmdQueue_Clear(@)
[0-100]: The brightness level before the off command was sent. This allows the light to turn back on to the last brightness level.
-
- RGB
+ rgb
[FFFFFF]: HEX value for RGB.
-
@@ -1809,6 +2172,9 @@ sub MilightDevice_CmdQueue_Clear(@)
-
toggle
+ -
+ night
+
-
dim <percent(0..100)> [seconds(0..x)] [flags(l=long path|q=don't clear queue)]
@@ -1891,9 +2257,6 @@ sub MilightDevice_CmdQueue_Clear(@)
-
rgb
- -
- RGB
-
-
hsv
@@ -1918,6 +2281,26 @@ sub MilightDevice_CmdQueue_Clear(@)
presets
List of hsv presets separated by spaces (eg 0,0,100 9,0,50).
+ -
+ colorCast
+ Color shift values for red,yellow,green,cyan,blue,magenta (-29..29) for HSV color correction (eg 0,5,10,-5,0,0)
+
+ -
+ gamma
+ Set gamma correction value for device (eg 0.8)
+
+ -
+ dimOffWhite
+ Use a different switching logic for White bulbs to better handle packet loss.
+
+ -
+ updateGroupDevices
+ Update the state of single devices switched with slot 'A'.
+
+ -
+ defaultBrightness
+ Set the default brightness if not known. (Default: 36)
+