mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-06 12:46:57 +00:00
5240 lines
204 KiB
Perl
5240 lines
204 KiB
Perl
##############################################
|
|
# $Id$
|
|
|
|
# TODO
|
|
|
|
# versions
|
|
# 00 POC
|
|
# ..
|
|
# 50 Stable
|
|
# 51 new milight color converter
|
|
# 52 timing for transitions: drop frames if required
|
|
# 53 transition names and events
|
|
# 54 drop frames ll add-on / lock ll queue
|
|
# 55 add ll queue lock count
|
|
# 56 RGB in
|
|
# 57 bridge v2
|
|
# 58 gamma correction
|
|
# 59 fix "off" with ramp
|
|
# 60 add dimup/dimdown
|
|
# 61 introduce dimSteps
|
|
# 62 introduce defaultColor
|
|
# 63 LW12 define if lw12 is unavailable at startup
|
|
# 64 transition with ramp 0 fixed
|
|
# 65 some typos with impact to RGBW1 and RGBW2
|
|
# 66 readings: lower camelCase and limited trigger
|
|
# 67 restore state after startup
|
|
# 68 LW12 reconnect after timeout
|
|
# 69 RGBW1 timing improved
|
|
# 70 colorpicker
|
|
# 71 default ramp attrib
|
|
# 72 add LD316
|
|
# 73 add LD382
|
|
# 74 add color calibration (hue intersections) for RGB type controller
|
|
# 75 add white point adjustment for RGB type controller
|
|
# 76 add LW12 HX001
|
|
# 77 milight RGBW2: critical cmds sendout repeatly
|
|
# 78 add attrib for color managment (rgb types)
|
|
# 79 add LD382 RGB ony mode
|
|
# 80 HSV2fourChannel bug fixed (thnx to lexorius)
|
|
# 81 LW12FC added
|
|
# 82 LD382A (FW 1.0.6)
|
|
# 83 fixed ramp handling (thnx to henryk)
|
|
# 84 sengled boost added (thnx to scooty)
|
|
# 85 milight white, improved reliability
|
|
# 86 milight white, improved reliability / mark II
|
|
# 87 milight rgbw2, dim bug
|
|
# 88 readingFnAttributes
|
|
# 89 add LD316A
|
|
# 90 Sunricher poc
|
|
# 91 milight colorcast fixed, more robust tcp re-connect
|
|
|
|
# verbose level
|
|
# 0: quit
|
|
# 1: error
|
|
# 2: warning
|
|
# 3: user command
|
|
# 4: 1st technical level (detailed internal reporting)
|
|
# 5: 2nd technical level (full internal reporting)
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use IO::Handle;
|
|
use IO::Socket;
|
|
use IO::Select;
|
|
use Time::HiRes;
|
|
use Data::Dumper;
|
|
|
|
use Color;
|
|
|
|
sub
|
|
WifiLight_Initialize(@)
|
|
{
|
|
|
|
my ($hash) = @_;
|
|
|
|
FHEM_colorpickerInit();
|
|
|
|
$hash->{DefFn} = "WifiLight_Define";
|
|
$hash->{UndefFn} = "WifiLight_Undef";
|
|
$hash->{ShutdownFn} = "WifiLight_Undef";
|
|
$hash->{SetFn} = "WifiLight_Set";
|
|
$hash->{GetFn} = "WifiLight_Get";
|
|
$hash->{AttrFn} = "WifiLight_Attr";
|
|
$hash->{NotifyFn} = "WifiLight_Notify";
|
|
$hash->{AttrList} = "gamma dimStep defaultColor defaultRamp colorCast whitePoint"
|
|
." $readingFnAttributes";
|
|
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_Define($$)
|
|
{
|
|
my ($hash, $def) = @_;
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
my $name = $a[0];
|
|
my $key;
|
|
|
|
return "wrong syntax: define <name> WifiLight <type> <connection>" if(@a != 4);
|
|
# return "unknown LED type ($a[2]): choose one of RGB, RGBW, RGBW1, RGBW2, White" unless (grep /$a[2]/, ('RGB', 'RGBW', 'RGBW1', 'RGBW2', 'White'));
|
|
|
|
$hash->{LEDTYPE} = $a[2];
|
|
my $otherLights;
|
|
|
|
if ($a[3] =~ m/(bridge-V2):([^:]+):*(\d+)*/g)
|
|
{
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:50000;
|
|
$hash->{PROTO} = 0;
|
|
#my @hlCmdQueue = [];
|
|
@{$hash->{helper}->{hlCmdQueue}} = (); #\@hlCmdQueue;
|
|
# $hash->{SERVICE} = 48899; unkown for v2
|
|
# search if this bridge is already defined
|
|
# if so, we need a shared buffer (llCmdQueue), shared socket and we need to check if the requied slot is free
|
|
foreach $key (keys %defs)
|
|
{
|
|
if (($defs{$key}{TYPE} eq 'WifiLight') && ($defs{$key}{IP} eq $hash->{IP}) && ($key ne $name))
|
|
{
|
|
#bridge is in use
|
|
Log3 (undef, 3, "WifiLight: requested bridge $hash->{CONNECTION} at $hash->{IP} already in use by $key, copy llCmdQueue");
|
|
$hash->{helper}->{llCmdQueue} = $defs{$key}{helper}{llCmdQueue};
|
|
$hash->{helper}->{llLock} = 0;
|
|
$hash->{helper}->{SOCKET} = $defs{$key}{helper}{SOCKET};
|
|
$hash->{helper}->{SELECT} = $defs{$key}{helper}{SELECT};
|
|
my $slotInUse = $defs{$key}{SLOT};
|
|
$otherLights->{$slotInUse} = $defs{$key};
|
|
}
|
|
}
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => 48899,
|
|
Blocking => 0,
|
|
Proto => 'udp',
|
|
Broadcast => 1) or return "can't bind: $@";
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = {};
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(bridge-V3):([^:]+):*(\d+)*/g)
|
|
{
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:8899;
|
|
$hash->{PROTO} = 0;
|
|
#my @hlCmdQueue = [];
|
|
@{$hash->{helper}->{hlCmdQueue}} = (); #\@hlCmdQueue;
|
|
# $hash->{SERVICE} = 48899;
|
|
# search if this bridge is already defined
|
|
# if so, we need a shared buffer (llCmdQueue), shared socket and we need to check if the requied slot is free
|
|
foreach $key (keys %defs)
|
|
{
|
|
if (($defs{$key}{TYPE} eq 'WifiLight') && ($defs{$key}{IP} eq $hash->{IP}) && ($defs{$key}{PORT} eq $hash->{PORT}) && ($key ne $name))
|
|
{
|
|
#bridge is in use
|
|
Log3 (undef, 3, "WifiLight: requested bridge $hash->{CONNECTION} at $hash->{IP} already in use by $key, copy llCmdQueue");
|
|
$hash->{helper}->{llCmdQueue} = $defs{$key}{helper}{llCmdQueue};
|
|
$hash->{helper}->{llLock} = 0;
|
|
$hash->{helper}->{SOCKET} = $defs{$key}{helper}{SOCKET};
|
|
$hash->{helper}->{SELECT} = $defs{$key}{helper}{SELECT};
|
|
my $slotInUse = $defs{$key}{SLOT};
|
|
$otherLights->{$slotInUse} = $defs{$key};
|
|
}
|
|
}
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => 48899,
|
|
Blocking => 0,
|
|
Proto => 'udp',
|
|
Broadcast => 1) or return "can't bind: $@";
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LW12):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGB supported by LW12" if ($a[2] ne "RGB");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5577;
|
|
$hash->{PROTO} = 1;
|
|
#$hash->{SERVICE} = 48899;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LW12HX):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGB supported by LW12HX" if ($a[2] ne "RGB");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5000;
|
|
$hash->{PROTO} = 1;
|
|
#$hash->{SERVICE} = 48899;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LW12FC):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGB supported by LW12FC" if ($a[2] ne "RGB");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5000;
|
|
#$hash->{PROTO} = 1;
|
|
#$hash->{SERVICE} = 48899;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Blocking => 0,
|
|
Proto => 'udp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LD316):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGBW supported by LD316" if ($a[2] ne "RGBW");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5577;
|
|
$hash->{PROTO} = 1;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LD316A):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGBW supported by LD316A" if ($a[2] ne "RGBW");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5577;
|
|
$hash->{PROTO} = 1;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LD382):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGB and RGBW supported by LD382" if (($a[2] ne "RGB") && ($a[2] ne "RGBW"));
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5577;
|
|
$hash->{PROTO} = 1;
|
|
#$hash->{SERVICE} = 48899;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(LD382A):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only RGB and RGBW supported by LD382A" if (($a[2] ne "RGB") && ($a[2] ne "RGBW"));
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:5577;
|
|
$hash->{PROTO} = 1;
|
|
#$hash->{SERVICE} = 48899;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(SENGLED):([^:]+):*(\d+)*/g)
|
|
{
|
|
return "only White supported by SENGLED" if ($a[2] ne "White");
|
|
$hash->{CONNECTION} = $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:9060;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Blocking => 0,
|
|
Proto => 'udp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(SUNRICHER):([^:]+):*(\d+)*/gi)
|
|
{
|
|
# return "only White, DualWhite, RGB, RGBW supported by Sunricher" if ($a[2] ne 'RGBW');
|
|
$hash->{CONNECTION} = uc $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:8899;
|
|
$hash->{PROTO} = 1;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
}
|
|
}
|
|
|
|
if ($a[3] =~ m/(SUNRICHERA):([^:]+):*(\d+)*/gi)
|
|
{
|
|
# return "only White, DualWhite, RGB, RGBW supported by Sunricher" if ($a[2] ne 'RGBW');
|
|
$hash->{CONNECTION} = uc $1;
|
|
$hash->{IP} = $2;
|
|
$hash->{PORT} = $3?$3:8899;
|
|
$hash->{PROTO} = 1;
|
|
$hash->{SLOT} = 0;
|
|
@{$hash->{helper}->{hlCmdQueue}} = ();
|
|
if (!defined($hash->{helper}->{SOCKET}))
|
|
{
|
|
my $sock = IO::Socket::INET-> new (
|
|
PeerPort => $hash->{PORT},
|
|
PeerAddr => $hash->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
|
|
my $select = IO::Select->new($sock);
|
|
$hash->{helper}->{SOCKET} = $sock;
|
|
$hash->{helper}->{SELECT} = $select;
|
|
@{$hash->{helper}->{llCmdQueue}} = ();
|
|
$hash->{helper}->{llLock} = 0;
|
|
}
|
|
}
|
|
|
|
return "unknown connection type, see documentation" if !(defined($hash->{CONNECTION}));
|
|
|
|
Log3 ($hash, 4, "define $a[0] $a[1] $a[2] $a[3]");
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12HX'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12FC'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.85);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 0.85, 0.55';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD316'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -25, -15, -25, 0, -20';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1.0, 0.6, 0.065';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD316A'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -25, -15, -25, 0, -20';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1.0, 0.6, 0.065';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD382'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LD382'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD382A'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LD382A'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10';
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
|
|
return undef;
|
|
}
|
|
|
|
if ((($hash->{LEDTYPE} eq 'RGB') || ($hash->{LEDTYPE} eq 'RGBW1')) && ($hash->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}" if (defined($otherLights->{0}));
|
|
$hash->{SLOT} = 0;
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 1);
|
|
$hash->{helper}->{COLORMAP} = WifiLight_Milight_ColorConverter($hash);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB sync pair unpair";
|
|
#if we are allready paired: sync to get a defined state
|
|
return WifiLight_RGB_Sync($hash) if ($hash->{LEDTYPE} eq 'RGB');
|
|
return WifiLight_RGBW1_Sync($hash) if ($hash->{LEDTYPE} eq 'RGBW1');
|
|
}
|
|
elsif (($hash->{LEDTYPE} eq 'RGBW2') && ($hash->{CONNECTION} =~ 'bridge-V3'))
|
|
{
|
|
# find a free slot
|
|
my $i = 5;
|
|
while (defined($otherLights->{$i}))
|
|
{
|
|
$i++;
|
|
}
|
|
if ( grep { $i == $_ } 5..8 )
|
|
{
|
|
$hash->{SLOT} = $i;
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.73);
|
|
$hash->{helper}->{COLORMAP} = WifiLight_Milight_ColorConverter($hash);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB sync pair unpair";
|
|
return WifiLight_RGBW2_Sync($hash);
|
|
}
|
|
else
|
|
{
|
|
return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}";
|
|
}
|
|
}
|
|
elsif (($hash->{LEDTYPE} eq 'White') && ($hash->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
# find a free slot
|
|
my $i = 1;
|
|
while (defined($otherLights->{$i}))
|
|
{
|
|
$i++;
|
|
}
|
|
if ( grep { $i == $_ } 1..4 )
|
|
{
|
|
$hash->{SLOT} = $i;
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.8);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown sync pair unpair";
|
|
return WifiLight_White_Sync($hash);
|
|
}
|
|
else
|
|
{
|
|
return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}";
|
|
}
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'White') && ($hash->{CONNECTION} =~ 'SENGLED'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 1);
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown";
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'DualWhite') && ($hash->{CONNECTION} eq 'SUNRICHER'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown";
|
|
$hash->{helper}->{wLevel} = 0;
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
# my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
|
|
# $attr{$name}{"colorCast"} = $cc;
|
|
# WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
# $attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} eq 'SUNRICHER'))
|
|
{
|
|
$hash->{helper}->{COMMANDSET} = 'on off dim dimup dimdown HSV HSVK CT RGB';
|
|
# init helper
|
|
$hash->{helper}->{rLevel} = 0;
|
|
$hash->{helper}->{gLevel} = 0;
|
|
$hash->{helper}->{bLevel} = 0;
|
|
# init converter
|
|
$hash->{helper}->{cmd_pwr} = 'RGBSunricher_setPWR';
|
|
$hash->{helper}->{cmd_hsv} = 'RGBSunricher_setHSV';
|
|
# defaults
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
|
|
# color cast defaults
|
|
my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
|
|
$attr{$name}{"colorCast"} = '0, -20, -20, -25, 0, -10';
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
# TODO init readings
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} eq 'SUNRICHERA'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
$hash->{helper}->{rLevel} = 0;
|
|
$hash->{helper}->{gLevel} = 0;
|
|
$hash->{helper}->{bLevel} = 0;
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} eq 'SUNRICHER'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
$hash->{helper}->{rLevel} = 0;
|
|
$hash->{helper}->{gLevel} = 0;
|
|
$hash->{helper}->{bLevel} = 0;
|
|
$hash->{helper}->{wLevel} = 0;
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} eq 'SUNRICHERA'))
|
|
{
|
|
$hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
|
|
$hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
|
|
$hash->{helper}->{rLevel} = 0;
|
|
$hash->{helper}->{gLevel} = 0;
|
|
$hash->{helper}->{bLevel} = 0;
|
|
$hash->{helper}->{wLevel} = 0;
|
|
# color cast defaults in r,y, g, c, b, m: +/-30°
|
|
my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
|
|
$attr{$name}{"colorCast"} = $cc;
|
|
WifiLight_RGB_ColorConverter($hash, split(',', $cc));
|
|
# white point defaults in r,g,b
|
|
$attr{$name}{"whitePoint"} = '1, 1, 1';
|
|
return undef;
|
|
}
|
|
|
|
return "$hash->{LEDTYPE} is not supported at $hash->{CONNECTION} ($hash->{IP})";
|
|
}
|
|
|
|
sub
|
|
WifiLight_Undef(@)
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_Set(@)
|
|
{
|
|
my ($ledDevice, $name, $cmd, @args) = @_;
|
|
my $descriptor = '';
|
|
|
|
# remove descriptor from @args
|
|
for (my $i = $#args; $i >= 0; --$i )
|
|
{
|
|
if ($args[$i] =~ /\/d\:(.*)/)
|
|
{
|
|
$descriptor = $1;
|
|
splice (@args, $i, 1);
|
|
}
|
|
}
|
|
|
|
my $cnt = @args;
|
|
my $ramp = 0;
|
|
my $flags = "";
|
|
my $event = undef;
|
|
|
|
my $cmdSet = $ledDevice->{helper}->{COMMANDSET};
|
|
return "unknown command ($cmd): choose one of ".join(", ", $cmdSet) if ($cmd eq "?");
|
|
return "unknown command ($cmd): choose one of ".$ledDevice->{helper}->{COMMANDSET} if ($cmd ne 'RGB') and not ( grep { $cmd eq $_ } split(" ", $ledDevice->{helper}->{COMMANDSET} ));
|
|
|
|
if ($cmd eq 'pair')
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
if (defined($args[0]))
|
|
{
|
|
return "usage: set $name pair [seconds]" if ($args[0] !~ /^\d+$/);
|
|
$ramp = $args[0];
|
|
}
|
|
return WifiLight_RGB_Pair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Pair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Pair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
|
|
return WifiLight_White_Pair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'White');
|
|
}
|
|
|
|
if ($cmd eq 'unpair')
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
if (defined($args[0]))
|
|
{
|
|
return "usage: set $name unpair [seconds]" if ($args[0] !~ /^\d+$/);
|
|
$ramp = $args[0];
|
|
}
|
|
return WifiLight_RGB_UnPair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_UnPair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_UnPair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
|
|
return WifiLight_White_UnPair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'White');
|
|
}
|
|
|
|
if ($cmd eq 'sync')
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
return WifiLight_RGB_Sync($ledDevice) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Sync($ledDevice) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Sync($ledDevice) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
|
|
return WifiLight_White_Sync($ledDevice) if ($ledDevice->{LEDTYPE} eq 'White');
|
|
}
|
|
|
|
if (($cmd eq 'HSV') || ($cmd eq 'RGB') || ($cmd eq 'dim'))
|
|
{
|
|
$args[1] = AttrVal($ledDevice->{NAME}, "defaultRamp", 0) if !defined($args[1]);
|
|
}
|
|
else
|
|
{
|
|
$args[0] = AttrVal($ledDevice->{NAME}, "defaultRamp", 0) if !defined($args[0]);
|
|
}
|
|
|
|
if ($cmd eq 'on')
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
if (defined($args[0]))
|
|
{
|
|
return "usage: set $name on [seconds]" if ($args[0] !~ /^\d?.?\d+$/);
|
|
$ramp = $args[0];
|
|
}
|
|
return WifiLight_RGBWLD316_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
|
|
return WifiLight_RGBLW12HX_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
|
|
return WifiLight_RGBLW12FC_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
|
|
return WifiLight_WhiteSENGLED_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
|
|
return WifiLight_White_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
}
|
|
|
|
if ($cmd eq 'off')
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
if (defined($args[0]))
|
|
{
|
|
return "usage: set $name off [seconds]" if ($args[0] !~ /^\d?.?\d+$/);
|
|
$ramp = $args[0];
|
|
}
|
|
return WifiLight_RGBWLD316_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
|
|
return WifiLight_RGBLW12HX_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
|
|
return WifiLight_RGBLW12FC_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
|
|
return WifiLight_WhiteSENGLED_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
|
|
return WifiLight_White_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
}
|
|
|
|
if ($cmd eq 'dimup')
|
|
{
|
|
return "usage: set $name dimup" if (defined($args[1]));
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
my $v = ReadingsVal($ledDevice->{NAME}, "brightness", 0) + AttrVal($ledDevice->{NAME}, "dimStep", 7);
|
|
$v = 100 if $v > 100;
|
|
return WifiLight_RGBWLD316_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
|
|
return WifiLight_RGBLW12HX_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
|
|
return WifiLight_RGBLW12FC_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
|
|
return WifiLight_WhiteSENGLED_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
|
|
return WifiLight_White_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
}
|
|
|
|
if ($cmd eq 'dimdown')
|
|
{
|
|
return "usage: set $name dimdown" if (defined($args[1]));
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice);
|
|
my $v = ReadingsVal($ledDevice->{NAME}, "brightness", 0) - AttrVal($ledDevice->{NAME}, "dimStep", 7);
|
|
$v = 0 if $v < 0;
|
|
return WifiLight_RGBWLD316_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
|
|
return WifiLight_RGBLW12HX_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
|
|
return WifiLight_RGBLW12FC_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
|
|
return WifiLight_WhiteSENGLED_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
|
|
return WifiLight_White_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
}
|
|
|
|
if ($cmd eq 'dim')
|
|
{
|
|
return "usage: set $name dim level [seconds]" if ($args[0] !~ /^\d+$/);
|
|
return "usage: set $name dim level [seconds]" if (($args[0] < 0) || ($args[0] > 100));
|
|
if (defined($args[1]))
|
|
{
|
|
return "usage: set $name dim level [seconds] [q]" if ($args[1] !~ /^\d?.?\d+$/);
|
|
$ramp = $args[1];
|
|
}
|
|
if (defined($args[2]))
|
|
{
|
|
return "usage: set $name dim level seconds [q]" if ($args[2] !~ m/.*[qQ].*/);
|
|
$flags = $args[2];
|
|
}
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice) if ($flags !~ m/.*[qQ].*/);
|
|
return WifiLight_RGBWLD316_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
|
|
return WifiLight_RGBLW12HX_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
|
|
return WifiLight_RGBLW12FC_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
|
|
return WifiLight_WhiteSENGLED_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
|
|
return WifiLight_White_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
}
|
|
|
|
if (($cmd eq 'HSV') || ($cmd eq 'RGB'))
|
|
{
|
|
my ($hue, $sat, $val);
|
|
|
|
if ($cmd eq 'HSV')
|
|
{
|
|
return "HSV is required as h,s,v" if (defined($args[0]) && $args[0] !~ /^\d{1,3},\d{1,3},\d{1,3}$/);
|
|
($hue, $sat, $val) = split(',', $args[0]);
|
|
return "wrong hue ($hue): valid range 0..360" if !(($hue >= 0) && ($hue <= 360));
|
|
return "wrong saturation ($sat): valid range 0..100" if !(($sat >= 0) && ($sat <= 100));
|
|
return "wrong brightness ($val): valid range 0..100" if !(($val >= 0) && ($val <= 100));
|
|
}
|
|
elsif ($cmd eq 'RGB')
|
|
{
|
|
return "RGB is required hex RRGGBB" if (defined($args[0]) && $args[0] !~ /^[0-9A-Fa-f]{6}$/);
|
|
($hue, $sat, $val) = WifiLight_RGB2HSV($ledDevice, $args[0]);
|
|
}
|
|
|
|
if (defined($args[1]))
|
|
{
|
|
return "usage: set $name HSV H,S,V seconds flags programm" if ($args[1] !~ /^\d?.?\d+$/);
|
|
$ramp = $args[1];
|
|
}
|
|
if (defined($args[2]))
|
|
{
|
|
return "usage: set $name HSV H,S,V seconds [slq] programm" if ($args[2] !~ m/.*[sSlLqQ].*/);
|
|
$flags = $args[2];
|
|
}
|
|
if (defined($args[3]))
|
|
{
|
|
return "usage: set $name HSV H,S,V seconds flags programm=[A-Za-z_0-9]" if ($args[3] !~ m/[A-Za-z_0-9]*/);
|
|
$event = $args[3];
|
|
}
|
|
WifiLight_HighLevelCmdQueue_Clear($ledDevice) if ($flags !~ m/.*[qQ].*/);
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD316');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD316A');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD382');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD382A');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12HX');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12FC');
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 500, $event) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 1000, $event) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 200, $event) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
return WifiLight_SetHSV_Target($ledDevice, $hue, $sat, $val);
|
|
}
|
|
}
|
|
|
|
sub
|
|
WifiLight_Get(@)
|
|
{
|
|
my ($ledDevice, $name, $cmd, @args) = @_;
|
|
my $cnt = @args;
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_Attr(@)
|
|
{
|
|
my ($cmd, $device, $attribName, $attribVal) = @_;
|
|
my $ledDevice = $defs{$device};
|
|
|
|
if ($cmd eq 'set' && $attribName eq 'gamma')
|
|
{
|
|
return "gamma is required as numerical value (eg. 0.5 or 2.2)" if ($attribVal !~ /^\d*\.\d*$/);
|
|
$ledDevice->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($ledDevice, $attribVal);
|
|
}
|
|
if ($cmd eq 'set' && $attribName eq 'dimStep')
|
|
{
|
|
return "dimStep is required as numerical value [1..100]" if ($attribVal !~ /^\d*$/) || (($attribVal < 1) || ($attribVal > 100));
|
|
}
|
|
if ($cmd eq 'set' && $attribName eq 'defaultColor')
|
|
{
|
|
return "defaultColor is required as HSV" if ($attribVal !~ /^\d{1,3},\d{1,3},\d{1,3}$/);
|
|
my ($hue, $sat, $val) = split(',', $attribVal);
|
|
return "defaultColor: wrong hue ($hue): valid range 0..360" if !(($hue >= 0) && ($hue <= 360));
|
|
return "defaultColor: wrong saturation ($sat): valid range 0..100" if !(($sat >= 0) && ($sat <= 100));
|
|
return "defaultColor: wrong brightness ($val): valid range 0..100" if !(($val >= 0) && ($val <= 100));
|
|
}
|
|
my @a = ();
|
|
if ($cmd eq 'set' && $attribName eq 'colorCast')
|
|
{
|
|
@a = split(',', $attribVal);
|
|
my $msg = "colorCast: correction require 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);
|
|
}
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD316');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD316A');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD382');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD382A');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12HX');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12FC');
|
|
WifiLight_Milight_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]');
|
|
WifiLight_RGB_ColorConverter($ledDevice, @a) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
|
|
if ($init_done && !(@{$ledDevice->{helper}->{hlCmdQueue}}))
|
|
{
|
|
my $hue = $ledDevice->{READINGS}->{hue}->{VAL};
|
|
my $sat = $ledDevice->{READINGS}->{saturation}->{VAL};
|
|
my $val = $ledDevice->{READINGS}->{brightness}->{VAL};
|
|
WifiLight_setHSV($ledDevice, $hue, $sat, $val, 1);
|
|
}
|
|
}
|
|
if ($cmd eq 'set' && $attribName eq 'whitePoint')
|
|
{
|
|
@a = split(',', $attribVal);
|
|
my $msg = "whitePoint: correction require red, green, blue (each in a range of 0.0 ..1.0)";
|
|
return $msg unless (@a == 3);
|
|
foreach my $tc (@a)
|
|
{
|
|
return $msg unless ($tc =~ m/^\s*[0-9]+?[\.]{0,1}[0-9]*\s*$/g);
|
|
return $msg if (($tc < 0) || ($tc > 1));
|
|
}
|
|
if ($init_done && !(@{$ledDevice->{helper}->{hlCmdQueue}}))
|
|
{
|
|
$attr{$device}{"whitePoint"} = $attribVal;
|
|
my $hue = $ledDevice->{READINGS}->{hue}->{VAL};
|
|
my $sat = $ledDevice->{READINGS}->{saturation}->{VAL};
|
|
my $val = $ledDevice->{READINGS}->{brightness}->{VAL};
|
|
WifiLight_setHSV($ledDevice, $hue, $sat, $val, 1);
|
|
}
|
|
}
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} attrib $attribName $cmd $attribVal") if $attribVal;
|
|
return undef;
|
|
}
|
|
|
|
# restore previous settings (as set statefile)
|
|
sub
|
|
WifiLight_Notify(@)
|
|
{
|
|
my ($ledDevice, $eventSrc) = @_;
|
|
my $events = deviceEvents($eventSrc, 1);
|
|
my ($hue, $sat, $val);
|
|
|
|
# wait for global: INITIALIZED after start up
|
|
if ($eventSrc->{NAME} eq 'global' && @{$events}[0] eq 'INITIALIZED')
|
|
{
|
|
#######################################################
|
|
# TODO remove in a few weeks. its here for convenience
|
|
delete($ledDevice->{READINGS}->{HUE});
|
|
delete($ledDevice->{READINGS}->{SATURATION});
|
|
delete($ledDevice->{READINGS}->{BRIGHTNESS});
|
|
#######################################################
|
|
if ($ledDevice->{CONNECTION} eq 'LW12')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBLW12_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LW12HX')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBLW12HX_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LW12FC')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBLW12FC_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LD316')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBWLD316_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LD316A')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBWLD316A_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LD382')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBWLD382_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif ($ledDevice->{CONNECTION} eq 'LD382A')
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBWLD382A_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:60;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:100;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
|
|
return WifiLight_RGB_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:50;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
|
|
return WifiLight_RGBW1_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
|
|
return WifiLight_RGBW2_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
|
|
return WifiLight_White_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
|
|
return WifiLight_WhiteSENGLED_setHSV($ledDevice, $hue, $sat, $val);
|
|
}
|
|
elsif (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/))
|
|
{
|
|
$hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
|
|
$sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
|
|
$val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
|
|
return WifiLight_RGBSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
|
|
return WifiLight_RGBWSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBWSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
|
|
}
|
|
#
|
|
else
|
|
{
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# generic device types
|
|
# RGB device
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
|
|
sub
|
|
WifiLight_RGBDevice_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
|
|
my $delay = 50;
|
|
my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
|
|
my $receiver;
|
|
|
|
$on = WifiLight_Sunricher_Checksum($ledDevice, $on);
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
|
|
# TODO device specific on
|
|
|
|
my ($h, $s, $v, $k) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100, 3200"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBDevice_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set off $ramp");
|
|
return WifiLight_RGBDevice_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBDevice_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions DualWhite SUNRICHER
|
|
#
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
|
|
sub
|
|
WifiLight_DualWhiteSunricher_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
|
|
my $delay = 50;
|
|
my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
|
|
my $receiver;
|
|
|
|
$on = WifiLight_Sunricher_Checksum($ledDevice, $on);
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher set on ($v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_DualWhiteSunricher_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher set off $ramp");
|
|
return WifiLight_DualWhiteSunricher_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_DualWhiteSunricher_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_DualWhiteSunricher_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $ct) = @_;
|
|
my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 0;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} DualWhite Sunricher set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
my $wt = int($gammaVal * 0x40 / 100);
|
|
|
|
my $msg;
|
|
# Me$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x36, 0x10, 0x00, 0xAA, 0xAA));
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x33, $wt, 0x00, 0xAA, 0xAA));
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGBW SUNRICHER
|
|
# device range 0x00 0xff
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
|
|
sub
|
|
WifiLight_RGBSunricher_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
|
|
my $delay = 50;
|
|
my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
|
|
my $receiver;
|
|
|
|
$on = WifiLight_Sunricher_Checksum($ledDevice, $on);
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBSunricher_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set off $ramp");
|
|
return WifiLight_RGBWLD382_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBSunricher_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# SUNRICHER Color conversation functions
|
|
#
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBSunricher_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 0;
|
|
my $msg = '';
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
|
|
$rr = int( $rr * 0x80 / 0xFF );
|
|
$rg = int( $rg * 0x80 / 0xFF );
|
|
$rb = int( $rb * 0x80 / 0xFF );
|
|
$white = int( $white * 0x80 / 0xFF );
|
|
|
|
# TODO CT and white point correction
|
|
$rr += $white;
|
|
$rg += $white;
|
|
$rb += $white;
|
|
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
|
|
|
|
$ledDevice->{helper}->{rLevel} = $rr;
|
|
$ledDevice->{helper}->{rLevel} = $rg;
|
|
$ledDevice->{helper}->{rLevel} = $rb;
|
|
|
|
# leave here if nothing to tell
|
|
return unless $msg;
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
sub
|
|
WifiLight_RGBSunricherA_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 0;
|
|
my $msg = '';
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
|
|
# TODO CT and white point correction
|
|
$rr += $white;
|
|
$rg += $white;
|
|
$rb += $white;
|
|
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
|
|
|
|
$ledDevice->{helper}->{rLevel} = $rr;
|
|
$ledDevice->{helper}->{rLevel} = $rg;
|
|
$ledDevice->{helper}->{rLevel} = $rb;
|
|
|
|
# leave here if nothing to tell
|
|
return unless $msg;
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWSunricher_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 0;
|
|
my $msg = '';
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
|
|
$rr = int( $rr * 0x80 / 0xFF );
|
|
$rg = int( $rg * 0x80 / 0xFF );
|
|
$rb = int( $rb * 0x80 / 0xFF );
|
|
$white = int( $white * 0x80 / 0xFF );
|
|
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x21, $white, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{wLevel} != $white);
|
|
|
|
$ledDevice->{helper}->{rLevel} = $rr;
|
|
$ledDevice->{helper}->{rLevel} = $rg;
|
|
$ledDevice->{helper}->{rLevel} = $rb;
|
|
$ledDevice->{helper}->{rLevel} = $white;
|
|
|
|
# leave here if nothing to tell
|
|
return unless $msg;
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWSunricherA_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 0;
|
|
my $msg = '';
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
|
|
$rr *= 0x80 / 0xFF;
|
|
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
|
|
$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x21, $white, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{wLevel} != $white);
|
|
|
|
$ledDevice->{helper}->{rLevel} = $rr;
|
|
$ledDevice->{helper}->{rLevel} = $rg;
|
|
$ledDevice->{helper}->{rLevel} = $rb;
|
|
$ledDevice->{helper}->{rLevel} = $white;
|
|
|
|
# leave here if nothing to tell
|
|
return unless $msg;
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# SUNRICHER helper functions
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_Sunricher_Checksum(@)
|
|
{
|
|
my ($ledDevice, $msg) = @_;
|
|
|
|
my @byteStream = unpack('C*', $msg);
|
|
my $l = @byteStream;
|
|
my $c = 0;
|
|
|
|
for (my $i=4; $i<($l-3); $i++) {
|
|
$c += $byteStream[$i];
|
|
}
|
|
$c %= 0x100;
|
|
$byteStream[$l -3] = $c;
|
|
$msg = pack('C*', @byteStream);
|
|
return $msg;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGBW LD316
|
|
# aka XScource
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBWLD316_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 set off $ramp");
|
|
return WifiLight_RGBWLD316_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $k) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD316 set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction, may be doing it after wb more ok
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
##########################################
|
|
# sat is spread by 10% so there is room
|
|
# for a smoth switch to white and adapt to
|
|
# higher brightness of white led
|
|
##########################################
|
|
|
|
$sat = ($sat * 1.1) -10;
|
|
my $wl = ($sat<0)?$sat * -1:0;
|
|
$sat = ($sat<0)?0:$sat;
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my $msg;
|
|
|
|
##########################################
|
|
# experimental white temp adjustment
|
|
# G - 50%
|
|
# B - 04%
|
|
# sat is spread by 10% so there is room
|
|
# for a smoth switch to white and adapt to
|
|
# higher brightness of whte led
|
|
##########################################
|
|
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
# rgb mode
|
|
if (($val > 0) && ($wl == 0))
|
|
{
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
#new proto 0x56, r, g, b, white level, f0 (color) || 0f (white), 0xaa (terminator)
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x56, $rr, $rg, $rb, 0x00, 0xF0, 0xAA);
|
|
}
|
|
elsif ($wl > 0)
|
|
{
|
|
#smoth brightness adaption of white led
|
|
my $wo = $gammaVal - ($gammaVal * (10-$wl) * 0.08); #0.07
|
|
$wo = int(0.5 + ($wo * 2.55));
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x56, 0, 0, 0, $wo, 0x0F, 0xAA);
|
|
}
|
|
else
|
|
{
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x56, 0, 0, 0, 0x00, 0xF0, 0xAA);
|
|
}
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGBW LD316A - new fw.
|
|
# thnx raspklaus
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBWLD316A_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316A_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A set off $ramp");
|
|
return WifiLight_RGBWLD316_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316A_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD316A_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD316A set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction, may be doing it after wb more ok
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
##########################################
|
|
# sat is spread by 10% so there is room
|
|
# for a smoth switch to white and adapt to
|
|
# higher brightness of white led
|
|
##########################################
|
|
|
|
$sat = ($sat * 1.1) -10;
|
|
my $wl = ($sat<0)?$sat * -1:0;
|
|
$sat = ($sat<0)?0:$sat;
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my $msg;
|
|
|
|
##########################################
|
|
# experimental white temp adjustment
|
|
# G - 50%
|
|
# B - 04%
|
|
# sat is spread by 10% so there is room
|
|
# for a smoth switch to white and adapt to
|
|
# higher brightness of whte led
|
|
##########################################
|
|
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
# rgb mode
|
|
if (($val > 0) && ($wl == 0))
|
|
{
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
#new proto 0x56, r, g, b, white level, f0 (color) || 0f (white), 0xaa (terminator)
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0xF0, 0x0F);
|
|
}
|
|
elsif ($wl > 0)
|
|
{
|
|
#smoth brightness adaption of white led
|
|
my $wo = $gammaVal - ($gammaVal * (10-$wl) * 0.08); #0.07
|
|
$wo = int(0.5 + ($wo * 2.55));
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x31, 0, 0, 0, $wo, 0x0F, 0x0F);
|
|
}
|
|
else
|
|
{
|
|
$msg = sprintf("%c%c%c%c%c%c%c", 0x31, 0, 0, 0, 0x00, 0xF0, 0x0F);
|
|
}
|
|
#add checksum
|
|
$msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions LD382 aka Magic UFO
|
|
# with RGBW stripe (RGB and white)
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBWLD382_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c", 0x71, 0x23, 0x94);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 set off $ramp");
|
|
return WifiLight_RGBWLD382_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD382 set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, $white, 0x00, 0x00);
|
|
#add checksum
|
|
$msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382_Checksum(@)
|
|
{
|
|
my ($ledDevice, $msg) = @_;
|
|
my $c = 0;
|
|
foreach my $w (split //, $msg)
|
|
{
|
|
$c += ord($w);
|
|
}
|
|
$c %= 0x100;
|
|
$msg .= sprintf("%c", $c);
|
|
return $msg;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions LD382 aka Magic UFO
|
|
# with RGB stripe (mixed white)
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBLD382_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c", 0x71, 0x23, 0x94);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 set off $ramp");
|
|
return WifiLight_RGBLD382_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LD382 set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0x00, 0x00);
|
|
#add checksum
|
|
$msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions LD382A aka Magic UFO
|
|
# with RGBW stripe (RGB and white)
|
|
# LD382A is a LD382 with fw 1.0.6
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBWLD382A_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
|
|
# my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382A_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A set off $ramp");
|
|
return WifiLight_RGBWLD382A_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382A_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBWLD382A_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD382A set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, $white, 0x00, 0x0F);
|
|
#add checksum
|
|
$msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions LD382A aka Magic UFO
|
|
# with RGB stripe (mixed white)
|
|
# LD382A is a LD382 with fw 1.0.6
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBLD382A_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
|
|
# my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382A_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A set off $ramp");
|
|
return WifiLight_RGBLD382A_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382A_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLD382A_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LD382A set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0x00, 0x0F);
|
|
#add checksum
|
|
$msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGB LW12
|
|
# LED Stripe controller LW12
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBLW12_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
my $receiver;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
# WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
#TODO set physical off: my $off = sprintf("%c%c%c", 0xCC, 0x24, 0x33);
|
|
sub
|
|
WifiLight_RGBLW12_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 set off $ramp");
|
|
return WifiLight_RGBLW12_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12 set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
#new style converter with white point correction
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
my $msg = sprintf("%c%c%c%c%c", 0x56, $rr, $rg, $rb, 0xAA);
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGB LW12 HX001 Version
|
|
# LED Stripe controller LW12
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBLW12HX_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
# my $delay = 50;
|
|
# my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
|
|
# my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
|
|
# my $receiver;
|
|
# WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
# WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12HX set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12HX_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12HX set off $ramp");
|
|
return WifiLight_RGBLW12HX_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12HX_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBHX LW12 dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12HX_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12 set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
#new style converter with white point correction
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
#replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
my $on = ($gammaVal > 0)?1:0;
|
|
my $dim = 100;
|
|
|
|
# supported by ichichich
|
|
my @sendData = (0x9D, 0x62, 0x00, 0x01, 0x01, $on, $dim, $rr, $rg, $rb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
|
my $chkSum = 0xFF;
|
|
$chkSum += $_ for @sendData[3, 5..9];
|
|
unless ($chkSum == 0)
|
|
{
|
|
$chkSum %= 0xFF;
|
|
$chkSum = 0xFF if ($chkSum == 0);
|
|
}
|
|
push (@sendData, $chkSum);
|
|
for (my $i=2; $i<11; $i++)
|
|
{
|
|
my $h = ($sendData[$i] & 0xF0) + ($sendData[21-$i] >> 4);
|
|
my $l = (($sendData[$i] & 0x0F) << 4) + ($sendData[21-$i] & 0x0F);
|
|
|
|
$sendData[$i] = $h;
|
|
$sendData[21-$i] = $l;
|
|
}
|
|
my $msg = pack('C*', @sendData);
|
|
# $dbgStr = unpack("H*", $msg);
|
|
# print "lw12HX $dbgStr \n";
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGB LW12 FC Version
|
|
# LED Stripe controller LW12
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBLW12FC_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my $delay = 50;
|
|
my $on = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x04, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xEF);
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12FC_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC set off $ramp");
|
|
return WifiLight_RGBLW12FC_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12FC_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBLW12FC_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12FC set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
# color cast correction
|
|
my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
|
|
|
|
# new style converter with white point correction
|
|
my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
|
|
my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
|
|
# replace the removed part of white light and apply white balance
|
|
$rr += int(($white * $wr) + 0.5);
|
|
$rg += int(($white * $wg) + 0.5);
|
|
$rb += int(($white * $wb) + 0.5);
|
|
|
|
my $on = ($gammaVal > 0)?1:0;
|
|
my $dim = 100;
|
|
|
|
my $msg = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x07, 0x05, 0x03, $rr, $rg, $rb, 0x00, 0xEF);
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue
|
|
return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions White SENGLED
|
|
# E27 LED Bulb with
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_WhiteSENGLED_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
# my $delay = 50;
|
|
# my $on = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x04, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xEF);
|
|
# my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
# WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
|
|
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_WhiteSENGLED_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED set off $ramp");
|
|
return WifiLight_WhiteSENGLED_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_WhiteSENGLED_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
# my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
# my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, 0, 0, $level, $ramp, $flags, 100, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_WhiteSENGLED_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 50;
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} White SENGLED set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
my @remote = split(/\./, $ledDevice->{helper}->{SOCKET}->peerhost());
|
|
|
|
# intro
|
|
my $msg = sprintf("%c%c%c%c%c", 0x0d, 0x00, 0x02, 0x00, 0x01);
|
|
# sender, lazy 0x00
|
|
$msg .= sprintf("%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
|
|
# destinations
|
|
$msg .= sprintf("%c%c%c%c", $remote[0], $remote[1], $remote[2], $remote[3] );
|
|
# sender, lazy 0x00
|
|
$msg .= sprintf("%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
|
|
# destinations
|
|
$msg .= sprintf("%c%c%c%c", $remote[0], $remote[1], $remote[2], $remote[3] );
|
|
# intro 2
|
|
$msg .= sprintf("%c%c%c%c%c%c", 0x01, 0x00, 0x01, 0x00, 0x00, 0x00);
|
|
# cmd level
|
|
$msg .= sprintf("%c%c", $gammaVal, 0x64);
|
|
|
|
# for safety of tranmission (udp): repeat cmd if its stand-alone or first or last in transition
|
|
my $repeat = ($isLast)?3:1;
|
|
for (my $i=0; $i<$repeat; $i++)
|
|
{
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
|
|
# unlock ll queue after complete cmd is send
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGB
|
|
# LED Stripe or bulb, no white, controller V2
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGB_Pair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds) = @_;
|
|
$numSeconds = 3 if (($numSeconds || 0) == 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LED slot $ledDevice->{SLOT} pair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = "\x25\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_UnPair(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $numSeconds = 8;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LED slot $ledDevice->{SLOT} unpair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = "\x25\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_Sync(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
|
|
$ledDevice->{helper}->{whiteLevel} =9;
|
|
$ledDevice->{helper}->{colorLevel} =9;
|
|
$ledDevice->{helper}->{colorValue} =127;
|
|
$ledDevice->{helper}->{mode} =2; # mode 0: off, 1: mixed "white", 2: color
|
|
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, 500); # on
|
|
for (my $i = 0; $i < 22; $i++) {
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode up (to "pure white" ;-)
|
|
}
|
|
for (my $i = 0; $i < 10; $i++) {
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up (to "pure white" ;-)
|
|
}
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20\x7F\x55", $receiver, $delay); # color yellow (auto jump to mode 2)
|
|
for (my $i = 0; $i < 10; $i++) {
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up (yellow max brightness)
|
|
}
|
|
|
|
WifiLight_setHSV_Readings($ledDevice, 60, 100, 100) if $init_done;
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "40,100,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 500, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set off $ramp");
|
|
return WifiLight_RGB_Dim($ledDevice, 0, $ramp, '');
|
|
#TODO remove if tested
|
|
#return WifiLight_HSV_Transition($ledDevice, 0, 100, 0, $ramp, undef, 500, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 500, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set h:$hue, s:$sat, v:$val");
|
|
$sat = 100;
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# convert to device specs
|
|
my ($cv, $cl, $wl) = WifiLight_RGBW1_ColorConverter($ledDevice, $hue, $sat, $val);
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set levels: $cv, $cl, $wl");
|
|
return WifiLight_RGB_setLevels($ledDevice, $cv, $cl, $wl);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_setLevels(@)
|
|
{
|
|
my ($ledDevice, $cv, $cl, $wl) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
my $lock = 0;
|
|
|
|
# mode 0: off, 1: mixed "white", 2: color
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || ($ledDevice->{helper}->{colorLevel} != $cl) || ($ledDevice->{helper}->{whiteLevel} != $wl))
|
|
{
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
$lock = 1;
|
|
}
|
|
# need to touch color value (only if visible) or color level ?
|
|
if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || $ledDevice->{helper}->{colorLevel} != $cl)
|
|
{
|
|
# if color all off switch on
|
|
if ($ledDevice->{helper}->{mode} == 0)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{colorLevel} = 1;
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
elsif ($ledDevice->{helper}->{mode} == 1)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
else
|
|
{
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
}
|
|
# cl decrease
|
|
if ($ledDevice->{helper}->{colorLevel} > $cl)
|
|
{
|
|
for (my $i=$ledDevice->{helper}->{colorLevel}; $i > $cl; $i--)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
|
|
$ledDevice->{helper}->{colorLevel} = $i - 1;
|
|
}
|
|
if ($cl == 0)
|
|
{
|
|
# need to switch off color
|
|
# if no white is required and no white is active we can must entirely switch off
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 0;
|
|
}
|
|
}
|
|
# cl inrease
|
|
if ($ledDevice->{helper}->{colorLevel} < $cl)
|
|
{
|
|
for (my $i=$ledDevice->{helper}->{colorLevel}; $i < $cl; $i++)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
|
|
$ledDevice->{helper}->{colorLevel} = $i + 1;
|
|
}
|
|
}
|
|
}
|
|
# unlock ll queue
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1) if $lock;
|
|
return undef;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific controller functions RGBW1
|
|
# LED Stripe with extra white led, controller V2, bridge V2|bridge V3
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBW1_Pair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds) = @_;
|
|
$numSeconds = 3 if (($numSeconds || 0) == 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 LED slot $ledDevice->{SLOT} pair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = "\x25\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_UnPair(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $numSeconds = 8;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 LED slot $ledDevice->{SLOT} unpair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = "\x25\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_Sync(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 250;
|
|
|
|
$ledDevice->{helper}->{whiteLevel} =9;
|
|
$ledDevice->{helper}->{colorLevel} =9;
|
|
$ledDevice->{helper}->{colorValue} =170;
|
|
$ledDevice->{helper}->{mode} =3; # mode 0: c:off, w:off; 1: c:on, w:off; 2: c:off, w:on; 3: c:on, w:on
|
|
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, 500); # on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20\xAA\x55", $receiver, $delay); # color red (auto jump to mode 1 except we are mode 3)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (now we are for sure in mode 1)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #1
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #2
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #3
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #4
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #5
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #6
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #7
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #8
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #9 (highest dim-level color red)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (pure white)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #1
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #2
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #3
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #4
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #5
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #6
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #7
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #8
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #9 (highest dim-level white)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (white and red at highest level: bright warm light)
|
|
|
|
WifiLight_setHSV_Readings($ledDevice, 0, 50, 100) if $init_done;
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 1000, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set off $ramp");
|
|
return WifiLight_RGBW1_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 1000, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set h:$hue, s:$sat, v:$val");
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
|
|
# convert to device specs
|
|
my ($cv, $cl, $wl) = WifiLight_RGBW1_ColorConverter($ledDevice, $hue, $sat, $val);
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set levels: $cv, $cl, $wl");
|
|
return WifiLight_RGBW1_setLevels($ledDevice, $cv, $cl, $wl);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_setLevels(@)
|
|
{
|
|
my ($ledDevice, $cv, $cl, $wl) = @_;
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 250;
|
|
my $lock = 0;
|
|
|
|
# need to touch color value or color level?
|
|
# yes
|
|
# is color visible ? (we are in mode 1 or 3)
|
|
# yes: adjust color!, requ level = 1 if cl = 0; new level 0 ? yes: mode 0 if wl == 0 else Mode = 1 (if coming from 0 or 1 then wl =1)
|
|
# no:
|
|
# will we need color ?
|
|
# yes: go into mode #1, (cl jumps to 1)
|
|
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || ($ledDevice->{helper}->{colorLevel} != $cl) || ($ledDevice->{helper}->{whiteLevel} != $wl))
|
|
{
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
$lock = 1;
|
|
}
|
|
|
|
# need to touch color value (only if visible) or color level ?
|
|
if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || $ledDevice->{helper}->{colorLevel} != $cl)
|
|
{
|
|
# if color all off switch on
|
|
if ($ledDevice->{helper}->{mode} == 0)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down: 3 > 2 || 2 > 1
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down: 2 > 1 || 1 > 1
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{colorLevel} = 1;
|
|
$ledDevice->{helper}->{mode} = 1;
|
|
}
|
|
elsif ($ledDevice->{helper}->{mode} == 2)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up: 2 > 3
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{colorLevel} = 1;
|
|
$ledDevice->{helper}->{mode} = 3;
|
|
}
|
|
else
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
}
|
|
|
|
# color level decrease
|
|
if ($ledDevice->{helper}->{colorLevel} > $cl)
|
|
{
|
|
for (my $i=$ledDevice->{helper}->{colorLevel}; $i > $cl; $i--)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
|
|
$ledDevice->{helper}->{colorLevel} = $i - 1;
|
|
}
|
|
if ($cl == 0)
|
|
{
|
|
# need to switch off color
|
|
# if no white is required and no white is active switch off
|
|
if (($wl == 0) && ($ledDevice->{helper}->{mode} == 1))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 0;
|
|
}
|
|
# if white is required, goto mode 2: pure white
|
|
if (($wl > 0) || ($ledDevice->{helper}->{mode} == 2) || ($ledDevice->{helper}->{mode} == 3))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{mode} == 1) ; # mode up
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{mode} == 3) ; # mode down
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{whiteLevel} = 1 if ($ledDevice->{helper}->{mode} == 1);
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
}
|
|
}
|
|
if ($ledDevice->{helper}->{colorLevel} < $cl)
|
|
{
|
|
for (my $i=$ledDevice->{helper}->{colorLevel}; $i < $cl; $i++)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
|
|
$ledDevice->{helper}->{colorLevel} = $i + 1;
|
|
}
|
|
}
|
|
}
|
|
# need to adjust white level ?
|
|
if ($ledDevice->{helper}->{whiteLevel} != $wl)
|
|
{
|
|
# white off but need adjustment ? set it on..
|
|
# color processing is finished, so if we are in mode 0, no color required. go to mode 2: pure white
|
|
if ($ledDevice->{helper}->{mode} == 0)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (3 -> 2 || 2 -> 1)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (2 -> 1 || 1 -> 1)
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (1 -> 2)
|
|
$ledDevice->{helper}->{whiteLevel} = 1;
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
# color processing is finished, so if we are at mode 1 color is required. go to mode 2
|
|
if ($ledDevice->{helper}->{mode} == 1)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (1 -> 2)
|
|
$ledDevice->{helper}->{whiteLevel} = 1;
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
# temporary go to mode 2 while maintain white level
|
|
if ($ledDevice->{helper}->{mode} == 3)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (3 -> 2)
|
|
$ledDevice->{helper}->{mode} = 2;
|
|
}
|
|
# white level inrease
|
|
for (my $i=$ledDevice->{helper}->{whiteLevel}; $i < $wl; $i++)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
|
|
$ledDevice->{helper}->{whiteLevel} = $i + 1;
|
|
}
|
|
# white level decrease
|
|
if ($ledDevice->{helper}->{whiteLevel} > $wl)
|
|
{
|
|
for (my $i=$ledDevice->{helper}->{whiteLevel}; $i > $wl; $i--)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
|
|
$ledDevice->{helper}->{whiteLevel} = $i - 1;
|
|
}
|
|
}
|
|
|
|
# assume we are at mode 2, finishing to correct mode
|
|
if (($wl == 0) && ($cl == 0))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
|
|
$ledDevice->{helper}->{whiteLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 0;
|
|
}
|
|
if (($wl == 0) && ($cl > 0))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (2 -> 1)
|
|
$ledDevice->{helper}->{whiteLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 1;
|
|
}
|
|
if (($wl > 0) && ($cl > 0))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (2 -> 3)
|
|
$ledDevice->{helper}->{mode} = 3;
|
|
}
|
|
}
|
|
# unlock ll queue
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1) if $lock;
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW1_ColorConverter(@)
|
|
{
|
|
my ($ledDevice, $h, $s, $v) = @_;
|
|
my $color = $ledDevice->{helper}->{COLORMAP}[$h % 360];
|
|
|
|
# there are 0..9 dim level, setup correction
|
|
my $valueSpread = 100/9;
|
|
my $totalVal = int(($v / $valueSpread) +0.5);
|
|
# saturation 100..50: color full, white increase. 50..0 white full, color decrease
|
|
my $colorVal = ($s >= 50) ? $totalVal : int(($s / 50 * $totalVal) +0.5);
|
|
my $whiteVal = ($s >= 50) ? int(((100-$s) / 50 * $totalVal) +0.5) : $totalVal;
|
|
return ($color, $colorVal, $whiteVal);
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific functions RGBW2 bulb
|
|
# RGB white, only bridge V3
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_RGBW2_Pair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds) = @_;
|
|
$numSeconds = 3 if (($numSeconds || 0) == 0);
|
|
my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: pair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_UnPair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds, $releaseFromSlot) = @_;
|
|
$numSeconds = 5;
|
|
my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: unpair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_Sync(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
# force new settings
|
|
$ledDevice->{helper}->{mode} = -1;
|
|
$ledDevice->{helper}->{colorValue} = -1;
|
|
$ledDevice->{helper}->{colorLevel} = -1;
|
|
$ledDevice->{helper}->{whiteLevel} = -1;
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 200, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set off $ramp");
|
|
return WifiLight_RGBW2_Dim($ledDevice, 0, $ramp, '');
|
|
#TODO remove if tested
|
|
#return WifiLight_HSV_Transition($ledDevice, 0, 0, 0, $ramp, undef, 500, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} dim $level $ramp ". $flags || '');
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 200, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGBW2_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
|
|
my ($cl, $wl);
|
|
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
my $cv = $ledDevice->{helper}->{COLORMAP}[$hue % 360];
|
|
|
|
# apply gamma correction
|
|
my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
|
|
|
|
# mode 0 = off, 1 = color, 2 = white
|
|
# brightness 2..27 (x02..x1b) | 25
|
|
my $cf = 100 / 26;
|
|
my $cb = int(($gammaVal / $cf) + 0.5);
|
|
$cb += ($cb > 0)?1:0;
|
|
|
|
if ($sat < 20)
|
|
{
|
|
$wl = $cb;
|
|
$cl = 0;
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, 0, $val);
|
|
}
|
|
else
|
|
{
|
|
$cl = $cb;
|
|
$wl = 0;
|
|
WifiLight_setHSV_Readings($ledDevice, $hue, 100, $val);
|
|
}
|
|
|
|
return WifiLight_RGBW2_setLevelsFast($ledDevice, $receiver, $cv, $cl, $wl) unless ($isLast);
|
|
return WifiLight_RGBW2_setLevelsSafe($ledDevice, $receiver, $cv, $cl, $wl);
|
|
}
|
|
|
|
# repeatly send out a full size cmd
|
|
# the last cmd in a transition or if it is stand alone
|
|
sub
|
|
WifiLight_RGBW2_setLevelsSafe(@)
|
|
{
|
|
my ($ledDevice, $receiver, $cv, $cl, $wl) = @_;
|
|
my $delay = 100;
|
|
|
|
my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
|
|
my @bulbCmdsOff = ("\x46", "\x48", "\x4A", "\x4C");
|
|
my @bulbCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB");
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set safe levels");
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} lock queue ".$ledDevice->{helper}->{llLock});
|
|
|
|
my @cmd = ();
|
|
|
|
# about switching off. dim to prevent a flash if switched on again
|
|
|
|
if (($wl == 0) && ($cl == 0) && ($ledDevice->{helper}->{mode} != 0))
|
|
{
|
|
$ledDevice->{helper}->{llLock} += 1; # lock ...
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # group on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E\x02\x55", $receiver, $delay); # brightness
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1); # ... unlock
|
|
}
|
|
|
|
if (($wl == 0) && ($cl == 0))
|
|
{
|
|
push (@cmd, @bulbCmdsOff[$ledDevice->{SLOT} -5]."\x00\x55");
|
|
$ledDevice->{helper}->{whiteLevel} = 0;
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 0; # group off
|
|
}
|
|
elsif ($wl > 0)
|
|
{
|
|
push (@cmd, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55");
|
|
push (@cmd, @bulbCmdsWT[$ledDevice->{SLOT} -5]."\x00\x55");
|
|
push (@cmd, "\x4E".chr($wl)."\x55");
|
|
$ledDevice->{helper}->{whiteLevel} = $wl;
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 2; # white
|
|
}
|
|
elsif ($cl > 0)
|
|
{
|
|
push (@cmd, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55");
|
|
push (@cmd, "\x40".chr($cv)."\x55"); # color
|
|
push (@cmd, "\x4E".chr($cl)."\x55"); # brightness
|
|
$ledDevice->{helper}->{whiteLevel} = 0;
|
|
$ledDevice->{helper}->{colorLevel} = $cl;
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{mode} = 1; # color
|
|
}
|
|
|
|
# repeat it three times
|
|
for (my $i=0; $i<3; $i++)
|
|
{
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $_, $receiver, $delay) foreach (@cmd);
|
|
# unlock ll queue after complete cmd is send
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
# classic optimized version, used by fast color transitions
|
|
sub
|
|
WifiLight_RGBW2_setLevelsFast(@)
|
|
{
|
|
my ($ledDevice, $receiver, $cv, $cl, $wl) = @_;
|
|
my $delay = 100;
|
|
|
|
my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
|
|
my @bulbCmdsOff = ("\x46", "\x48", "\x4A", "\x4C");
|
|
my @bulbCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB");
|
|
|
|
return if (($ledDevice->{helper}->{colorValue} == $cv) && ($ledDevice->{helper}->{colorLevel} == $cl) && ($ledDevice->{helper}->{whiteLevel} == $wl));
|
|
# lock ll queue to prevent a bottleneck within llqueue
|
|
# in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
|
|
# this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
|
|
$ledDevice->{helper}->{llLock} += 1;
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} lock queue ".$ledDevice->{helper}->{llLock});
|
|
|
|
if (($wl == 0) && ($cl == 0) && ($ledDevice->{helper}->{mode} != 0))
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay);
|
|
$ledDevice->{helper}->{whiteLevel} = 0;
|
|
$ledDevice->{helper}->{colorLevel} = 0;
|
|
$ledDevice->{helper}->{mode} = 0; # group off
|
|
}
|
|
else
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # group on
|
|
# WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay) if (($wl > 0) || ($cl > 0)); # group on
|
|
if (($wl > 0) && ($ledDevice->{helper}->{mode} == 2)) # already white
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($wl)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{whiteLevel} != $wl); # brightness
|
|
}
|
|
elsif (($wl > 0) && ($ledDevice->{helper}->{mode} != 2)) # not white
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsWT[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # white
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($wl)."\x55", $receiver, $delay); # brightness
|
|
$ledDevice->{helper}->{mode} = 2; # white
|
|
}
|
|
elsif (($cl > 0) && ($ledDevice->{helper}->{mode} == 1)) # already color
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($cl)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{colorLevel} != $cl); # brightness
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x40".chr($cv)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{colorValue} != $cv); # color
|
|
}
|
|
elsif (($cl > 0) && ($ledDevice->{helper}->{mode} != 1)) # not color
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x40".chr($cv)."\x55", $receiver, $delay); # color
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($cl)."\x55", $receiver, $delay); # brightness
|
|
$ledDevice->{helper}->{mode} = 1; # color
|
|
}
|
|
$ledDevice->{helper}->{colorValue} = $cv;
|
|
$ledDevice->{helper}->{colorLevel} = $cl;
|
|
$ledDevice->{helper}->{whiteLevel} = $wl;
|
|
}
|
|
# unlock ll queue after complete cmd is send
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
|
|
return undef;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# device specific functions white bulb
|
|
# warm white / cold white with dim, bridge V2|bridge V3
|
|
#
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_White_Pair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds) = @_;
|
|
$numSeconds = 1 if !(defined($numSeconds));
|
|
my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: pair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_UnPair(@)
|
|
{
|
|
my ($ledDevice, $numSeconds, $releaseFromSlot) = @_;
|
|
$numSeconds = 5;
|
|
my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: unpair $numSeconds");
|
|
# find my slot and get my group-all-on cmd
|
|
my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55";
|
|
for (my $i = 0; $i < $numSeconds; $i++)
|
|
{
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_Sync(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
|
|
my @bulbCmdsFB = ("\xB8", "\xBD", "\xB7", "\xB2");
|
|
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
|
|
$ledDevice->{helper}->{whiteLevel} =11;
|
|
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: sync");
|
|
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsFB[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # full brightness
|
|
|
|
WifiLight_setHSV_Readings($ledDevice, 0, 0, 100) if $init_done;
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_On(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} set on $ramp");
|
|
return WifiLight_HSV_Transition($ledDevice, 0, 0, 100, $ramp, '', 500, undef);
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_Off(@)
|
|
{
|
|
my ($ledDevice, $ramp) = @_;
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} set off $ramp");
|
|
return WifiLight_RGBW2_Dim($ledDevice, 0, $ramp, '');
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_Dim(@)
|
|
{
|
|
my ($ledDevice, $level, $ramp, $flags) = @_;
|
|
my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} dim $level $ramp $flags");
|
|
return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 300, undef);
|
|
}
|
|
|
|
# only val supported,
|
|
# TODO hue will become colortemp
|
|
sub
|
|
WifiLight_White_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my $wlStep = (100 / 11);
|
|
WifiLight_setHSV_Readings($ledDevice, 0, 0, $val);
|
|
$val = int(($val / $wlStep) +0.5);
|
|
WifiLight_White_setLevels($ledDevice, undef, $val);
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_White_setLevels(@)
|
|
{
|
|
my ($ledDevice, $cv, $wl) = @_;
|
|
my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
|
|
my @bulbCmdsOff = ("\x3B", "\x33", "\x3A", "\x36");
|
|
my @bulbCmdsFull = ("\xB8", "\xBD", "\xB7", "\xB2");
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 80;
|
|
|
|
# alert that dump receiver, give it a extra wake up call
|
|
if ($ledDevice->{helper}->{whiteLevel} != $wl)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay);
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay);
|
|
}
|
|
|
|
if ($ledDevice->{helper}->{whiteLevel} > $wl)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
|
|
for (my $i=$ledDevice->{helper}->{whiteLevel}; $i > $wl; $i--)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
|
|
$ledDevice->{helper}->{whiteLevel} = $i - 1;
|
|
}
|
|
if ($wl == 0)
|
|
{
|
|
# special precaution, giving extra downsteps to do a sync each time you switch off
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group off
|
|
#WifiLight_LowLevelCmdqueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT}-1]."\x00\x55", $receiver, $delay);
|
|
}
|
|
}
|
|
|
|
if ($ledDevice->{helper}->{whiteLevel} < $wl)
|
|
{
|
|
$ledDevice->{helper}->{whiteLevel} = 1 if ($ledDevice->{helper}->{whiteLevel} == 0);
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
|
|
for (my $i=$ledDevice->{helper}->{whiteLevel}; $i < $wl; $i++)
|
|
{
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x3C\x00\x55", $receiver, $delay); # brightness up
|
|
$ledDevice->{helper}->{whiteLevel} = $i + 1;
|
|
}
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsFull[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{whiteLevel} == 11);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
|
|
###############################################################################
|
|
#
|
|
# device indepenent routines
|
|
#
|
|
###############################################################################
|
|
|
|
# dispatcher
|
|
sub
|
|
WifiLight_setHSV(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
|
|
return WifiLight_RGBWLD316_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
|
|
return WifiLight_RGBWLD316A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
|
|
return WifiLight_RGBWLD382_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBLD382_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
|
|
return WifiLight_RGBWLD382A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLD382A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
|
|
return WifiLight_RGBLW12_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12');
|
|
return WifiLight_RGBLW12HX_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12HX');
|
|
return WifiLight_RGBLW12FC_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12FC');
|
|
return WifiLight_WhiteSENGLED_setHSV($ledDevice, $hue, $sat, $val, $isLast) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
|
|
return WifiLight_RGB_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW1_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq "RGBW1") && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_RGBW2_setHSV($ledDevice, $hue, $sat, $val, $isLast) if ($ledDevice->{LEDTYPE} eq "RGBW2");
|
|
return WifiLight_White_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
|
|
return WifiLight_DualWhiteSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
|
|
return WifiLight_RGBWSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
|
|
return WifiLight_RGBWSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
|
|
return undef;
|
|
}
|
|
|
|
# dispatcher
|
|
sub
|
|
WifiLight_processEvent(@)
|
|
{
|
|
my ($ledDevice, $event, $progress) = @_;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} processEvent: $event, progress: $progress") if defined($event);
|
|
DoTrigger($ledDevice->{NAME}, "programm: $event $progress",0) if defined($event);
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_HSV_Transition(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $ramp, $flags, $delay, $event) = @_;
|
|
my ($hueFrom, $satFrom, $valFrom, $timeFrom);
|
|
|
|
# minimum stepwide
|
|
my $defaultDelay = $delay;
|
|
|
|
# if queue in progess set start vals to last cached hsv target, else set start to actual hsv
|
|
if (@{$ledDevice->{helper}->{hlCmdQueue}} > 0)
|
|
{
|
|
$hueFrom = $ledDevice->{helper}->{targetHue};
|
|
$satFrom = $ledDevice->{helper}->{targetSat};
|
|
$valFrom = $ledDevice->{helper}->{targetVal};
|
|
$timeFrom = $ledDevice->{helper}->{targetTime};
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} prepare start hsv transition (is cached) hsv $hueFrom, $satFrom, $valFrom, $timeFrom");
|
|
}
|
|
else
|
|
{
|
|
$hueFrom = $ledDevice->{READINGS}->{hue}->{VAL} || 0;
|
|
$satFrom = $ledDevice->{READINGS}->{saturation}->{VAL} || 0;
|
|
$valFrom = $ledDevice->{READINGS}->{brightness}->{VAL} || 0;
|
|
$timeFrom = gettimeofday();
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} prepare start hsv transition (is actual) hsv $hueFrom, $satFrom, $valFrom, $timeFrom");
|
|
}
|
|
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} current HSV $hueFrom, $satFrom, $valFrom");
|
|
Log3 ($ledDevice, 3, "$ledDevice->{NAME} set HSV $hue, $sat, $val with ramp: $ramp, flags: ". $flags);
|
|
|
|
# if there is no ramp we dont need transition
|
|
if (($ramp || 0) == 0)
|
|
{
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} hsv transition without ramp routed to direct settings, hsv $hue, $sat, $val");
|
|
$ledDevice->{helper}->{targetTime} = $timeFrom;
|
|
return WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $delay, 100, $event, $timeFrom);
|
|
}
|
|
|
|
# calculate the left and right turn length based
|
|
# startAngle +360 -endAngle % 360 = counter clock
|
|
# endAngle +360 -startAngle % 360 = clockwise
|
|
my $fadeLeft = ($hueFrom + 360 - $hue) % 360;
|
|
my $fadeRight = ($hue + 360 - $hueFrom) % 360;
|
|
my $direction = ($fadeLeft <=> $fadeRight); # -1 = counterclock, +1 = clockwise
|
|
$direction = ($direction == 0)?1:$direction; # in dupt cw
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} color rotation dev cc:$fadeLeft, cw:$fadeRight, shortest:$direction");
|
|
$direction *= -1 if ($flags =~ m/.*[lL].*/); # reverse if long path desired (flag l or L is set)
|
|
|
|
my $rotation = ($direction == 1)?$fadeRight:$fadeLeft; # angle of hue rotation in based on flags
|
|
my $sFade = abs($sat - $satFrom);
|
|
my $vFade = abs($val - $valFrom);
|
|
|
|
my ($stepWide, $steps, $hueToSet, $hueStep, $satToSet, $satStep, $valToSet, $valStep);
|
|
|
|
# fix if there is in fact no transition, blocks queue for given ramp time with actual hsv values
|
|
if ($rotation == 0 && $sFade == 0 && $vFade == 0)
|
|
{
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} hsv transition with unchaned settings, hsv $hue, $sat, $val, ramp $ramp");
|
|
#TODO remove if tested
|
|
#WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $ramp * 1000, 0, $event, $timeFrom);
|
|
|
|
$ledDevice->{helper}->{targetTime} = $timeFrom + $ramp;
|
|
return WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $delay, 100, $event, $timeFrom + $ramp);
|
|
}
|
|
|
|
if (($rotation >= $sFade) && ($rotation >= $vFade))
|
|
{
|
|
$stepWide = ($ramp * 1000 / $rotation); # how long is one step (set hsv) in ms based on hue
|
|
$stepWide = $defaultDelay if ($stepWide < $defaultDelay);
|
|
$steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (H>S||V) steps: $steps stepwide: $stepWide");
|
|
}
|
|
elsif (($sFade >= $rotation) && ($sFade >= $vFade))
|
|
{
|
|
$stepWide = ($ramp * 1000 / $sFade); # how long is one step (set hsv) in ms based on sat
|
|
$stepWide = $defaultDelay if ($stepWide < $defaultDelay);
|
|
$steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (S>H||V) steps: $steps stepwide: $stepWide");
|
|
}
|
|
else
|
|
{
|
|
$stepWide = ($ramp * 1000 / $vFade); # how long is one step (set hsv) in ms based on val
|
|
$stepWide = $defaultDelay if ($stepWide < $defaultDelay);
|
|
$steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (V>H||S) steps: $steps stepwide: $stepWide");
|
|
}
|
|
|
|
$hueToSet = $hueFrom; # prepare tmp working hue
|
|
$hueStep = $rotation / $steps * $direction; # how big is one hue step base on timing choosen
|
|
|
|
$satToSet = $satFrom; # prepare workin sat
|
|
$satStep = ($sat - $satFrom) / $steps;
|
|
|
|
$valToSet = $valFrom;
|
|
$valStep = ($val - $valFrom) / $steps;
|
|
|
|
#TODO do something more flexible
|
|
#TODO remove if tested
|
|
# $timeFrom += 1;
|
|
|
|
for (my $i=1; $i <= $steps; $i++)
|
|
{
|
|
$hueToSet += $hueStep;
|
|
$hueToSet -= 360 if ($hueToSet > 360); #handle turn over zero
|
|
$hueToSet += 360 if ($hueToSet < 0);
|
|
$satToSet += $satStep;
|
|
$valToSet += $valStep;
|
|
my $progress = 100 / $steps * $i;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} add to hl queue h:".($hueToSet).", s:".($satToSet).", v:".($valToSet)." ($i/$steps)");
|
|
WifiLight_HighLevelCmdQueue_Add($ledDevice, int($hueToSet +0.5), int($satToSet +0.5), int($valToSet +0.5), undef, $stepWide, int($progress +0.5), $event, $timeFrom + (($i-1) * $stepWide / 1000) );
|
|
}
|
|
$ledDevice->{helper}->{targetTime} = $timeFrom + $ramp;
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_SetHSV_Target(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
$ledDevice->{helper}->{targetHue} = $hue;
|
|
$ledDevice->{helper}->{targetSat} = $sat;
|
|
$ledDevice->{helper}->{targetVal} = $val;
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_setHSV_Readings(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val) = @_;
|
|
my ($r, $g, $b) = WifiLight_HSV2RGB($hue, $sat, $val);
|
|
readingsBeginUpdate($ledDevice);
|
|
readingsBulkUpdate($ledDevice, "hue", $hue % 360);
|
|
readingsBulkUpdate($ledDevice, "saturation", $sat);
|
|
readingsBulkUpdate($ledDevice, "brightness", $val);
|
|
readingsBulkUpdate($ledDevice, "RGB", sprintf("%02X%02X%02X",$r,$g,$b));
|
|
readingsBulkUpdate($ledDevice, "state", "on") if ($val > 0);
|
|
readingsBulkUpdate($ledDevice, "state", "off") if ($val == 0);
|
|
readingsEndUpdate($ledDevice, 1);
|
|
}
|
|
|
|
sub
|
|
WifiLight_HSV2RGB(@)
|
|
{
|
|
my ($hue, $sat, $val) = @_;
|
|
|
|
if ($sat == 0)
|
|
{
|
|
return int(($val * 2.55) +0.5), int(($val * 2.55) +0.5), int(($val * 2.55) +0.5);
|
|
}
|
|
$hue %= 360;
|
|
$hue /= 60;
|
|
$sat /= 100;
|
|
$val /= 100;
|
|
|
|
my $i = int($hue);
|
|
|
|
my $f = $hue - $i;
|
|
my $p = $val * (1 - $sat);
|
|
my $q = $val * (1 - $sat * $f);
|
|
my $t = $val * (1 - $sat * (1 - $f));
|
|
|
|
my ($r, $g, $b);
|
|
|
|
if ( $i == 0 )
|
|
{
|
|
($r, $g, $b) = ($val, $t, $p);
|
|
}
|
|
elsif ( $i == 1 )
|
|
{
|
|
($r, $g, $b) = ($q, $val, $p);
|
|
}
|
|
elsif ( $i == 2 )
|
|
{
|
|
($r, $g, $b) = ($p, $val, $t);
|
|
}
|
|
elsif ( $i == 3 )
|
|
{
|
|
($r, $g, $b) = ($p, $q, $val);
|
|
}
|
|
elsif ( $i == 4 )
|
|
{
|
|
($r, $g, $b) = ($t, $p, $val);
|
|
}
|
|
else
|
|
{
|
|
($r, $g, $b) = ($val, $p, $q);
|
|
}
|
|
return (int(($r * 255) +0.5), int(($g * 255) +0.5), int(($b * 255) + 0.5));
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB2HSV(@)
|
|
{
|
|
my ($ledDevice, $in) = @_;
|
|
my $r = hex substr($in, 0, 2);
|
|
my $g = hex substr($in, 2, 2);
|
|
my $b = hex substr($in, 4, 2);
|
|
my ($max, $min, $delta);
|
|
my ($h, $s, $v);
|
|
|
|
$max = $r if (($r >= $g) && ($r >= $b));
|
|
$max = $g if (($g >= $r) && ($g >= $b));
|
|
$max = $b if (($b >= $r) && ($b >= $g));
|
|
$min = $r if (($r <= $g) && ($r <= $b));
|
|
$min = $g if (($g <= $r) && ($g <= $b));
|
|
$min = $b if (($b <= $r) && ($b <= $g));
|
|
|
|
$v = int(($max / 2.55) + 0.5);
|
|
$delta = $max - $min;
|
|
|
|
my $currentHue = ReadingsVal($ledDevice->{NAME}, "hue", 0);
|
|
return ($currentHue, 0, $v) if (($max == 0) || ($delta == 0));
|
|
|
|
$s = int((($delta / $max) *100) + 0.5);
|
|
$h = ($g - $b) / $delta if ($r == $max);
|
|
$h = 2 + ($b - $r) / $delta if ($g == $max);
|
|
$h = 4 + ($r - $g) / $delta if ($b == $max);
|
|
$h = int(($h * 60) + 0.5);
|
|
$h += 360 if ($h < 0);
|
|
return $h, $s, $v;
|
|
}
|
|
|
|
sub
|
|
WifiLight_HSV2fourChannel(@)
|
|
{
|
|
my ($h, $s, $v) = @_;
|
|
my ($r, $g, $b) = WifiLight_HSV2RGB($h, $s, $v);
|
|
#white part, base 255
|
|
my $white = 255;
|
|
foreach ($r, $g, $b) { $white = $_ if ($_ < $white); }
|
|
#remaining color part
|
|
my ($rr, $rg, $rb);
|
|
$rr = $r - $white;
|
|
$rg = $g - $white;
|
|
$rb = $b - $white;
|
|
return ($rr, $rg, $rb, $white);
|
|
}
|
|
|
|
sub
|
|
WifiLight_Milight_ColorConverter(@)
|
|
{
|
|
my ($ledDevice, $cr, $cy, $cg, $cc, $cb, $cm) = @_;
|
|
#my ($ledDevice) = @_;
|
|
|
|
my @colorMap;
|
|
|
|
#my $hueRed = 0;
|
|
my $adjRed = 0 - ($cr || 0);
|
|
#my $hueYellow = 60;
|
|
my $adjYellow = 60 - ($cy || 0);
|
|
#my $hueGreen = 120;
|
|
my $adjGreen = 120 - ($cg || 0);
|
|
#my $hueCyan = 180;
|
|
my $adjCyan = 180 - ($cc || 0);
|
|
#my $hueBlue = 240;
|
|
my $adjBlue = 240 - ($cb || 0);
|
|
#my $hueLilac = 300;
|
|
my $adjLilac = 300 - ($cm || 0);
|
|
|
|
#st34
|
|
my $devRed = 168;
|
|
#my $devRed = 176;
|
|
my $devYellow = 134;
|
|
#my $devYellow = 144;
|
|
my $devGreen = 88;
|
|
#my $devCyan = 48;
|
|
my $devCyan = 56;
|
|
my $devBlue = 8;
|
|
my $devLilac = 208; #224
|
|
|
|
my $i= 360;
|
|
|
|
# red to yellow
|
|
$adjRed += 360 if ($adjRed < 0); # in case of negative adjustment
|
|
$devRed += 256 if ($devRed < $devYellow);
|
|
$adjYellow += 360 if ($adjYellow < $adjRed);
|
|
for ($i = $adjRed; $i <= $adjYellow; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devRed - int((($devRed - $devYellow) / ($adjYellow - $adjRed) * ($i - $adjRed)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
#yellow to green
|
|
$devYellow += 256 if ($devYellow < $devGreen);
|
|
$adjGreen += 360 if ($adjGreen < $adjYellow);
|
|
for ($i = $adjYellow; $i <= $adjGreen; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devYellow - int((($devYellow - $devGreen) / ($adjGreen - $adjYellow) * ($i - $adjYellow)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
#green to cyan
|
|
$devGreen += 256 if ($devGreen < $devCyan);
|
|
$adjCyan += 360 if ($adjCyan < $adjGreen);
|
|
for ($i = $adjGreen; $i <= $adjCyan; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devGreen - int((($devGreen - $devCyan) / ($adjCyan - $adjGreen) * ($i - $adjGreen)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
#cyan to blue
|
|
$devCyan += 256 if ($devCyan < $devCyan);
|
|
$adjBlue += 360 if ($adjBlue < $adjCyan);
|
|
for ($i = $adjCyan; $i <= $adjBlue; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devCyan - int((($devCyan - $devBlue) / ($adjBlue - $adjCyan) * ($i - $adjCyan)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
#blue to lilac
|
|
$devBlue += 256 if ($devBlue < $devLilac);
|
|
$adjLilac += 360 if ($adjLilac < $adjBlue);
|
|
for ($i = $adjBlue; $i <= $adjLilac; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devBlue - int((($devBlue - $devLilac) / ($adjLilac - $adjBlue) * ($i- $adjBlue)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
#lilac to red
|
|
$devLilac += 256 if ($devLilac < $devRed);
|
|
$adjRed += 360 if ($adjRed < $adjLilac);
|
|
for ($i = $adjLilac; $i <= $adjRed; $i++)
|
|
{
|
|
$colorMap[$i % 360] = ($devLilac - int((($devLilac - $devRed) / ($adjRed - $adjLilac) * ($i - $adjLilac)) +0.5)) % 255;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
|
|
}
|
|
@{$ledDevice->{helper}->{COLORMAP}} = @colorMap;
|
|
return \@colorMap;
|
|
}
|
|
|
|
sub
|
|
WifiLight_RGB_ColorConverter(@)
|
|
{
|
|
# default correction +/- 29°
|
|
my ($ledDevice, $cr, $cy, $cg, $cc, $cb, $cm) = @_;
|
|
#my ($cr, $cy, $cg, $cc, $cb, $cm) = (0, -30, -10, -30, 0, -10);
|
|
|
|
my @colorMap;
|
|
|
|
for (my $i = 0; $i <= 360; $i++)
|
|
{
|
|
my $toR = WifiLight_HueDistance(0, $i);
|
|
my $toY = WifiLight_HueDistance(60, $i);
|
|
my $toG = WifiLight_HueDistance(120, $i);
|
|
my $toC = WifiLight_HueDistance(180, $i);
|
|
my $toB = WifiLight_HueDistance(240, $i);
|
|
my $toM = WifiLight_HueDistance(300, $i);
|
|
|
|
my $c = 0; # $i;
|
|
$c += $cr - ($cr * $toR / 60) if (abs($toR) <= 60);
|
|
$c += $cy - ($cy * $toY / 60) if (abs($toY) <= 60);
|
|
$c += $cg - ($cg * $toG / 60) if (abs($toG) <= 60);
|
|
$c += $cc - ($cc * $toC / 60) if (abs($toC) <= 60);
|
|
$c += $cb - ($cb * $toB / 60) if (abs($toB) <= 60);
|
|
$c += $cm - ($cm * $toM / 60) if (abs($toM) <= 60);
|
|
|
|
$colorMap[$i] = int($i + $c + 0.5) % 360;
|
|
|
|
#$colorMap[$i] = (int($colorMap[$i] + ($cr - ($cr * $toR / 45)) + 0.5) + 360) % 360 if (abs($toR) <= 45);
|
|
#$colorMap[$i] = (int($colorMap[$i] + ($cy - ($cy * $toY / 45)) + 0.5) + 360) % 360 if (abs($toY) <= 45);
|
|
#$colorMap[$i] = (int($colorMap[$i] + ($cg - ($cg * $toG / 45)) + 0.5) + 360) % 360 if (abs($toG) <= 45);
|
|
}
|
|
@{$ledDevice->{helper}->{COLORMAP}} = @colorMap;
|
|
return \@colorMap;
|
|
}
|
|
|
|
# calculate the distance of two given hue
|
|
sub
|
|
WifiLight_HueDistance(@)
|
|
{
|
|
my ($hue, $testHue) = @_;
|
|
my $a = (360 + $hue - $testHue) % 360;
|
|
my $b = (360 + $testHue - $hue) % 360;
|
|
return ($a, $b)[$a > $b];
|
|
}
|
|
|
|
# helper for easying access to attrib
|
|
sub
|
|
WifiLight_ccAttribVal(@)
|
|
{
|
|
my ($ledDevice, $dr, $dy, $dg, $dc, $db, $dm) = @_;
|
|
my $a = AttrVal($ledDevice->{NAME}, 'colorCast', undef);
|
|
if ($a)
|
|
{
|
|
my ($cr, $cy, $cg, $cc, $cb, $cm) = split (',', $a);
|
|
}
|
|
else
|
|
{
|
|
my ($cr, $cy, $cg, $cc, $cb, $cm) = ($dr, $dy, $dg, $dc, $db, $dm);
|
|
}
|
|
return ($dr, $dy, $dg, $dc, $db, $dm);
|
|
}
|
|
|
|
|
|
sub
|
|
WifiLight_CreateGammaMapping(@)
|
|
{
|
|
my ($ledDevice, $gamma) = @_;
|
|
|
|
my @gammaMap;
|
|
|
|
for (my $i = 0; $i <= 100; $i += 1)
|
|
{
|
|
my $correction = ($i / 100) ** (1 / $gamma);
|
|
$gammaMap[$i] = $correction * 100;
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} create gammamap v-in: ".$i.", v-out: $gammaMap[$i]");
|
|
}
|
|
|
|
return \@gammaMap;
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# high level queue, long running color transitions
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_HighLevelCmdQueue_Add(@)
|
|
{
|
|
my ($ledDevice, $hue, $sat, $val, $ctrl, $delay, $progress, $event, $targetTime) = @_;
|
|
my $cmd;
|
|
|
|
$cmd->{hue} = $hue;
|
|
$cmd->{sat} = $sat;
|
|
$cmd->{val} = $val;
|
|
# $cmd->{k} = $k;
|
|
$cmd->{ctrl} = $ctrl;
|
|
$cmd->{delay} = $delay;
|
|
$cmd->{progress} = $progress;
|
|
$cmd->{event} = $event;
|
|
$cmd->{targetTime} = $targetTime;
|
|
$cmd->{inProgess} = 0;
|
|
|
|
push @{$ledDevice->{helper}->{hlCmdQueue}}, $cmd;
|
|
|
|
my $dbgStr = unpack("H*", $cmd->{ctrl} || '');
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue add hsv/ctrl $cmd->{hue}, $cmd->{sat}, $cmd->{val}, ctrl $dbgStr, targetTime $cmd->{targetTime}, qlen ".@{$ledDevice->{helper}->{hlCmdQueue}});
|
|
|
|
my $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
|
|
|
|
# sender busy ?
|
|
return undef if (($actualCmd->{inProgess} || 0) == 1);
|
|
return WifiLight_HighLevelCmdQueue_Exec($ledDevice);
|
|
}
|
|
|
|
sub
|
|
WifiLight_HighLevelCmdQueue_Exec(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
|
|
|
|
# transmission complete, remove
|
|
shift @{$ledDevice->{helper}->{hlCmdQueue}} if ($actualCmd->{inProgess});
|
|
|
|
# next in queue
|
|
$actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
|
|
my $nextCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[1];
|
|
|
|
# return if no more elements in queue
|
|
return undef if (!defined($actualCmd->{inProgess}));
|
|
|
|
# drop frames if next frame is already sceduled for given time. do not drop if it is the last frame or if it is a command
|
|
while (defined($nextCmd->{targetTime}) && ($nextCmd->{targetTime} < gettimeofday()) && !$actualCmd->{ctrl})
|
|
{
|
|
shift @{$ledDevice->{helper}->{hlCmdQueue}};
|
|
$actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
|
|
$nextCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[1];
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec drop frame at hlQueue level. hl qlen: ".@{$ledDevice->{helper}->{hlCmdQueue}});
|
|
}
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} high level cmd queue exec dropper delay: ".($actualCmd->{targetTime} - gettimeofday()) );
|
|
|
|
# set hsv or if a device ctrl command is sceduled: send it and ignore hsv
|
|
if ($actualCmd->{ctrl})
|
|
{
|
|
my $dbgStr = unpack("H*", $actualCmd->{ctrl});
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec ctrl $dbgStr, qlen ".@{$ledDevice->{helper}->{hlCmdQueue}});
|
|
WifiLight_sendCtrl($ledDevice, $actualCmd->{ctrl});
|
|
}
|
|
else
|
|
{
|
|
my $isLast = (@{$ledDevice->{helper}->{hlCmdQueue}} == 1)?1:undef;
|
|
if (($ledDevice->{helper}->{llLock} == 0) || $isLast)
|
|
{
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec hsv $actualCmd->{hue}, $actualCmd->{sat}, $actualCmd->{val}, delay $actualCmd->{delay}, hl qlen ".@{$ledDevice->{helper}->{hlCmdQueue}}.", ll qlen ".@{$ledDevice->{helper}->{llCmdQueue}}.", lock ".$ledDevice->{helper}->{llLock});
|
|
WifiLight_setHSV($ledDevice, $actualCmd->{hue}, $actualCmd->{sat}, $actualCmd->{val}, $isLast);
|
|
}
|
|
else
|
|
{
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} high level cmd queue exec drop frame at llQueue level. ll qlen: ".@{$ledDevice->{helper}->{llCmdQueue}}.", lock ".$ledDevice->{helper}->{llLock});
|
|
}
|
|
}
|
|
$actualCmd->{inProgess} = 1;
|
|
my $next = defined($nextCmd->{targetTime})?$nextCmd->{targetTime}:gettimeofday() + ($actualCmd->{delay} / 1000);
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue ask next $next");
|
|
InternalTimer($next, "WifiLight_HighLevelCmdQueue_Exec", $ledDevice, 0);
|
|
WifiLight_processEvent($ledDevice, $actualCmd->{event}, $actualCmd->{progress});
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
WifiLight_HighLevelCmdQueue_Clear(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue clear");
|
|
RemoveInternalTimer($ledDevice, 'WifiLight_HighLevelCmdQueue_Exec');
|
|
$ledDevice->{helper}->{hlCmdQueue} = [];
|
|
}
|
|
|
|
# dispatcher for ctrl cmd
|
|
sub
|
|
WifiLight_sendCtrl(@)
|
|
{
|
|
my ($ledDevice, $ctrl) = @_;
|
|
# TODO adjust for all bridge types
|
|
if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
|
|
{
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
|
|
}
|
|
if ($ledDevice->{LEDTYPE} eq 'RGBW1')
|
|
{
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
|
|
}
|
|
if ($ledDevice->{LEDTYPE} eq 'RGBW2')
|
|
{
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 100;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
|
|
}
|
|
if ($ledDevice->{LEDTYPE} eq 'White')
|
|
{
|
|
my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
|
|
my $delay = 10;
|
|
WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
|
|
}
|
|
}
|
|
|
|
###############################################################################
|
|
#
|
|
# atomic low level udp communication to device
|
|
# required because there are timing requirements, mostly limitaions in processing speed of the bridge
|
|
# the commands should never be interrupted or canceled because some fhem readings are set in advance
|
|
#
|
|
###############################################################################
|
|
|
|
sub
|
|
WifiLight_LowLevelCmdQueue_Add(@)
|
|
{
|
|
my ($ledDevice, $command, $receiver, $delay, $unlock) = @_;
|
|
my $cmd;
|
|
|
|
$cmd->{command} = $command;
|
|
$cmd->{sender} = $ledDevice;
|
|
$cmd->{receiver} = $receiver;
|
|
$cmd->{delay} = $delay;
|
|
$cmd->{unlock} = $unlock;
|
|
$cmd->{inProgess} = 0;
|
|
|
|
# push cmd into queue
|
|
push @{$ledDevice->{helper}->{llCmdQueue}}, $cmd;
|
|
|
|
my $dbgStr = unpack("H*", $cmd->{command});
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} low level cmd queue add $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}});
|
|
|
|
my $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
|
|
|
|
# sender busy ?
|
|
return undef if ($actualCmd->{inProgess});
|
|
return WifiLight_LowLevelCmdQueue_Send($ledDevice);
|
|
}
|
|
|
|
sub
|
|
WifiLight_LowLevelCmdQueue_Send(@)
|
|
{
|
|
my ($ledDevice) = @_;
|
|
my $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
|
|
|
|
# transmission complete, remove
|
|
shift @{$ledDevice->{helper}->{llCmdQueue}} if ($actualCmd->{inProgess});
|
|
|
|
# next in queue
|
|
$actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
|
|
|
|
# remove a low level queue lock if present and get next
|
|
while (($actualCmd->{unlock} || 0) == 1)
|
|
{
|
|
$actualCmd->{sender}->{helper}->{llLock} -= 1;
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} | $actualCmd->{sender}->{NAME} unlock queue ".$actualCmd->{sender}->{helper}->{llLock});
|
|
shift @{$ledDevice->{helper}->{llCmdQueue}};
|
|
$actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
|
|
}
|
|
|
|
# return if no more elements in queue
|
|
return undef if (!defined($actualCmd->{command}));
|
|
|
|
my $dbgStr = unpack("H*", $actualCmd->{command});
|
|
Log3 ($ledDevice, 5, "$ledDevice->{NAME} low level cmd queue qlen ".@{$ledDevice->{helper}->{llCmdQueue}}.", send $dbgStr");
|
|
|
|
# TCP
|
|
if ($ledDevice->{PROTO})
|
|
{
|
|
if (!$ledDevice->{helper}->{SOCKET} || ($ledDevice->{helper}->{SELECT}->can_read(0) && !$ledDevice->{helper}->{SOCKET}->recv(my $data, 512)))
|
|
{
|
|
Log3 ($ledDevice, 4, "$ledDevice->{NAME} low level cmd queue send $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}}." connection refused: trying to reconnect");
|
|
|
|
if ($ledDevice->{helper}->{SOCKET}) {
|
|
$ledDevice->{helper}->{SOCKET}->shutdown(2);
|
|
$ledDevice->{helper}->{SOCKET}->close();
|
|
}
|
|
|
|
$ledDevice->{helper}->{SOCKET} = IO::Socket::INET-> new (
|
|
PeerPort => $ledDevice->{PORT},
|
|
PeerAddr => $ledDevice->{IP},
|
|
Timeout => 1,
|
|
Blocking => 0,
|
|
Proto => 'tcp') or Log3 ($ledDevice, 3, "$ledDevice->{NAME} low level cmd queue send ERROR $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}}." (reconnect giving up)");
|
|
$ledDevice->{helper}->{SELECT} = IO::Select->new($ledDevice->{helper}->{SOCKET}) if $ledDevice->{helper}->{SOCKET};
|
|
}
|
|
$ledDevice->{helper}->{SOCKET}->send($actualCmd->{command}) if $ledDevice->{helper}->{SOCKET};
|
|
}
|
|
else
|
|
{
|
|
# print "send: $ledDevice->{NAME} $dbgStr \n";
|
|
send($ledDevice->{helper}->{SOCKET}, $actualCmd->{command}, 0, $actualCmd->{receiver}) or Log3 ($ledDevice, 1, "$ledDevice->{NAME} low level cmd queue send ERROR $@ $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}});
|
|
}
|
|
|
|
$actualCmd->{inProgess} = 1;
|
|
my $msec = $actualCmd->{delay} / 1000;
|
|
InternalTimer(gettimeofday()+$msec, "WifiLight_LowLevelCmdQueue_Send", $ledDevice, 0);
|
|
return undef;
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item device
|
|
=item summary controls a large number of different LED types
|
|
=item summary_DE steuert eine große Anzahl unterschiedlicher LED Typen
|
|
=begin html
|
|
|
|
<a name="WifiLight"></a>
|
|
<h3>WifiLight</h3>
|
|
<ul>
|
|
<p>The module controls a large number of different "no name" LED types and provide a consistent interface.</p>
|
|
<p>Following types will be supported:</p>
|
|
|
|
<table>
|
|
<thead align="left">
|
|
<tr>
|
|
<th>
|
|
type / bridge
|
|
</th>
|
|
<th>
|
|
type
|
|
</th>
|
|
<th>
|
|
note
|
|
</th>
|
|
<th>
|
|
define signature
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
Milight RGB first generation
|
|
</td>
|
|
<td>
|
|
E27, stripe controller
|
|
</td>
|
|
<td>
|
|
*(1,2,a,C)
|
|
</td>
|
|
<td>
|
|
RGB bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight RGBW1 first generation
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
*(1,2,a)
|
|
</td>
|
|
<td>
|
|
RGBW1 bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight Dual White
|
|
</td>
|
|
<td>
|
|
E14, E27, GU10, stripe controller, Downlight
|
|
</td>
|
|
<td>
|
|
*(1,2,b,W,nK)
|
|
</td>
|
|
<td>
|
|
White bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight RGBW2 second generation
|
|
</td>
|
|
<td>
|
|
E14, E27, GU10, stripe controller, Downlight
|
|
</td>
|
|
<td>
|
|
*(2,b,CW,S20)
|
|
</td>
|
|
<td>
|
|
RGBW2 bridge-V3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12 first generation (SSID LEDNet...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12HX (SSID HX...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12HX
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12FC (SSID FC...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12FC
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316 in RGB mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD316
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316 in RGBW mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
*(S20)
|
|
</td>
|
|
<td>
|
|
RGBW LD316
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316A in RGBW mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
*(S20)
|
|
</td>
|
|
<td>
|
|
RGBW LD316A
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382 in RGB mode
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382 in RGBW mode
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGBW LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382A (FW 1.0.6+) in RGB mode
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382A (FW 1.0.6+) in RGBW mode
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGBW LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
SENGLED
|
|
</td>
|
|
<td>
|
|
E27 bulb with build-in WLAN repeater
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
White Sengled
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
SUNRICHER with RGBW
|
|
</td>
|
|
<td>
|
|
Controller
|
|
</td>
|
|
<td>
|
|
*(!!!)
|
|
</td>
|
|
<td>
|
|
RGBW Sunricher
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>
|
|
<small>
|
|
(1) milght brigbe V2, V3, V4<br />
|
|
(2) milight bridge V3, V4<br />
|
|
(a) one group per bridge<br />
|
|
(b) four independent group per bridge<br />
|
|
(nK) no color temp support (Kelvin)<br />
|
|
(C) pure color<br />
|
|
(W) pure white<br />
|
|
(CW) pure Color or pure white<br />
|
|
(S20) Saturation <20: switch to pure white channel<br />
|
|
(!!!) EXPERIMENTAL<br />
|
|
</p>
|
|
</small>
|
|
<p>
|
|
<table>
|
|
<tr>
|
|
<td>
|
|
<p><b>Color</b></p>
|
|
<p>Colors can be specified in RGB or HSV color space.</p>
|
|
<p>Color in <a name="WifiLight_Farbraum_HSV"><b>color space "HSV"</b></a> are completely and generally more intuitive than RGB.</p>
|
|
<p><b>H</b> (HUE: 0..360) are the basic color in a color wheel.
|
|
<ul>
|
|
<li>Red is at 0 °</li>
|
|
<li>Green at 120 °</li>
|
|
<li> Blue at 240 °</li>
|
|
</ul>
|
|
</p>
|
|
<p><b>S</b> (Saturation: 0..100) stands for the saturation of the color. A saturation of 100 means the color is "pure" or completely saturated. Blue, for example, with 100% saturation corresponds to RGB # 0000FF.</p>
|
|
<p><b>V</b> (Value: 0..100) indicates the brightness. A value of 50 states that "half brightness".</p>
|
|
</td>
|
|
<td>
|
|
<a name="WifiLight_Farbkreis">
|
|
<svg style="width:450px; height:320px;" viewBox="-100 -30 500 320">
|
|
<linearGradient id="linearColors1" x1="0" y1="0" x2="1" y2="1">
|
|
<stop offset="0%" stop-color="#FF0000"></stop>
|
|
<stop offset="100%" stop-color="#FFFF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors2" x1="0.5" y1="0" x2="0.5" y2="1">
|
|
<stop offset="0%" stop-color="#FFFF00"></stop>
|
|
<stop offset="100%" stop-color="#00FF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors3" x1="1" y1="0" x2="0" y2="1">
|
|
<stop offset="0%" stop-color="#00FF00"></stop>
|
|
<stop offset="100%" stop-color="#00FFFF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors4" x1="1" y1="1" x2="0" y2="0">
|
|
<stop offset="0%" stop-color="#00FFFF"></stop>
|
|
<stop offset="100%" stop-color="#0000FF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors5" x1="0.5" y1="1" x2="0.5" y2="0">
|
|
<stop offset="0%" stop-color="#0000FF"></stop>
|
|
<stop offset="100%" stop-color="#FF00FF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors6" x1="0" y1="1" x2="1" y2="0">
|
|
<stop offset="0%" stop-color="#FF00FF"></stop>
|
|
<stop offset="100%" stop-color="#FF0000"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors7" x1="152" y1="130" x2="152" y2="35" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#FF0000"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors8" x1="152" y1="130" x2="230" y2="190" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#00FF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors9" x1="152" y1="130" x2="70" y2="190" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#0000FF"></stop>
|
|
</linearGradient>
|
|
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
|
|
<path d="M2,2 L2,11 L10,6 L2,2" style="fill:grey;" />
|
|
</marker>
|
|
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="url(#linearColors1)" stroke-width="20" />
|
|
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="url(#linearColors2)" stroke-width="20" />
|
|
<path d="M253.9230 190 a120 120 0 0 1 -103.9230 60" fill="none" stroke="url(#linearColors3)" stroke-width="20" />
|
|
<path d="M150 250 a120 120 0 0 1 -103.9230 -60" fill="none" stroke="url(#linearColors4)" stroke-width="20" />
|
|
<path d="M46.077 190 a120 120 0 0 1 0 -120" fill="none" stroke="url(#linearColors5)" stroke-width="20" />
|
|
<path d="M46.077 70 a120 120 0 0 1 103.9230 -60" fill="none" stroke="url(#linearColors6)" stroke-width="20" />
|
|
<path d="M150,50 C250,50 250,180 180,200" fill="none" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
|
|
<text class="Label" x="126" y="208">HUE</text>
|
|
<line x1="152" y1="130" x2="152" y2="35" stroke="url(#linearColors7)" stroke-width="4" />
|
|
<line x1="136" y1="120" x2="136" y2="45" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
|
|
<text class="Label" x="96" y="96">SAT</text>
|
|
<line x1="152" y1="130" x2="230" y2="190" stroke="url(#linearColors8)" stroke-width="4" />
|
|
<line x1="152" y1="130" x2="70" y2="190" stroke="url(#linearColors9)" stroke-width="4" />
|
|
<text x="120" y="-10">0° (Red)</text>
|
|
<text x="270" y="60">60° (Yellow)</text>
|
|
<text x="270" y="220">120° (Green)</text>
|
|
<text x="110" y="285">180° (Cyan)</text>
|
|
<text x="-60" y="220">240° (Blue)</text>
|
|
<text x="-90" y="60">300° (Magenta)</text>
|
|
</svg>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>
|
|
<b>Color: HSV compared to RGB</b>
|
|
<p>
|
|
Normally, a color may be expressed in the HSV color space as well as in RGB color space.
|
|
<p>
|
|
Colors in the HSV color space usually seem more understandable.
|
|
To move a Green in the HSV color space a little more toward CYAN, simply increase the HUE value (angle) slightly.
|
|
In RGB color space, the same task is less intuitive to achieve by increasing blue.
|
|
<p>
|
|
Differences become clear in Transitions however.
|
|
In order to dim BLUE up the HSV Transitions 240,100,0 -> 240,100,100 would be used.
|
|
To slowly dim RED (brightness 0) to BLUE the Transition in the HSV color space is 0,100,0 -> 240,100,100.
|
|
In RGB color space (# 000000 -> # 0000FF) can not distinguish between the two versions.
|
|
Here (correctly, but probably differently than intended) would appear in both cases, a white (brightness 0) as an initial value.
|
|
</p>
|
|
|
|
<p><b>Define</b></p>
|
|
<ul>
|
|
<li>
|
|
<p><code>define <name> WifiLight <LED type> <bridgetype>:<IP|FQDN></code></p>
|
|
<p>
|
|
<i><u>example</u></i>
|
|
<ul>
|
|
<p>
|
|
<i>defines a milight RGBW2 (bulb or LED stripe controller) on a milight bridge version 3 or 4.
|
|
The LED is allocated to a maximum of 4 groups available per bridge in order of definition:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGBW2 bridge-V3:192.168.178.142</code>
|
|
</ul>
|
|
<ul>
|
|
<p>
|
|
<i>defines a LD382A Controller with RGBW stripe:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGBW LD382A:192.168.178.142</code>
|
|
</ul>
|
|
<ul>
|
|
<p>
|
|
<i>defines a LD382A Controller with RGB stripe:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGB LD382A:192.168.178.142</code>
|
|
</ul>
|
|
<p>WifiLight has a <a href="#WifiLight_Farbkalibrierung">"color calibration"</a>. Ideally, a calibration should be performed every time after a lamp change or after definition.</p>
|
|
</ul>
|
|
</li>
|
|
<p><b>Set</b></p>
|
|
<ul>
|
|
<li>
|
|
<p><code>set <name> <b>on</b> [ramp]</code></p>
|
|
<p>Turns on the device. It is either chosen 100% White or the color defined by the attribute "default color".
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>off</b> [ramp]</code></p>
|
|
<p>Turns of the device.
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dimup</b></code></p>
|
|
<p>Increases the brightness by a fixed amount. The attribute "dimStep" or the default "7" is applied.<br />
|
|
This command is useful to increase particularly the brightness by a wall switch or a remote control.
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>none</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dimdown</b></code></p>
|
|
<p>Decreases the brightness by a fixed amount. The attribute "dimStep" or the default "7" is applied.<br />
|
|
This command is useful to reduce particularly the brightness by a wall switch or a remote control.
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>none</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dim</b> level [ramp] [q]</code></p>
|
|
<p>Sets the brightness to the specified level (0..100).
|
|
This command also maintains the preset color even with "dim 0" (off) and then "dim xx" (turned on) at.
|
|
Therefore, it represents an alternative form to "off" / "on". The latter would always choose the "default color".
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>q</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>HSV</b> H,S,V [ramp] [s|l|q] [event]</code></p>
|
|
<p>Sets the color in the <a href="#WifiLight_Farbraum_HSV">HSV color space</a>. If the ramp is specified (as a time in seconds), the module calculates a soft color transition from the current color to the newly set.
|
|
<ul><i>For example, sets a saturated blue with half brightness:</i><br /><code>set wz.licht.decke HSV 240,100,50</code></ul>
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>s l q event</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>RGB</b> RRGGBB [ramp] [l|s|q] [event]</code></p>
|
|
<p>Sets the color in the RGB color space.
|
|
<p>Advanced options:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>s l q event</li>
|
|
</ul>
|
|
</p>
|
|
</ul>
|
|
</li>
|
|
<p><b>Meaning of Flags</b></p>
|
|
Certain commands (set) can be marked with special flags.
|
|
<p>
|
|
<ul>
|
|
<li>ramp:
|
|
<ul>
|
|
Time in seconds for a soft color or brightness transition. The soft transition starts at the currently visible color and is calculated for the specified.
|
|
</ul>
|
|
</li>
|
|
<li>s:
|
|
<ul>
|
|
(short, default). A smooth transition to another color is carried out in the <a href="#WifiLight_Farbkreis">"color wheel"</a> on the shortest path.
|
|
A transition from red to green lead by the shortest route through yellow.
|
|
</ul>
|
|
</li>
|
|
<li>l:
|
|
<ul>
|
|
(long). A smooth transition to another color is carried out in the <a href="#WifiLight_Farbkreis">"color wheel"</a> on the "long" way.
|
|
A transition from red to green then leads across magenta, blue, and cyan.
|
|
</ul>
|
|
</li>
|
|
<li>q:
|
|
<ul>
|
|
(queue). Commands with this flag are cached in an internal queue and will not run before the currently running soft transitions have been processed.
|
|
Commands without the flag will be processed immediately. In this case all running transitions are stopped immediately and the queue will be cleared.
|
|
</ul>
|
|
</li>
|
|
<li>event:
|
|
<ul>
|
|
designator ([A-Za-z_0-9])
|
|
<p>
|
|
WifiLight creates, when using this flag, during transitions to another color messages (events) in the form:
|
|
<p>
|
|
<code>WifiLight <NAME> programm: <EVENT> <XX></code>.
|
|
<p>
|
|
<EVENT> is the designator as specified in the flag.<br/>
|
|
<XX> is the progress (percentage) of the transition.<br/>
|
|
<p>
|
|
Depending on the total duration of the transition, the values from 0 to 100 will not completely go through but for 0% and 100% is guaranteed always a event.
|
|
To these events can then be reacted within a notify or DOIF to (for example):
|
|
<ul>
|
|
<li>increase the volume of a radio when a lamp is turned on in the morning slowly</li>
|
|
<li>A color transition can be restarted in a notify if it is complete (loop it, even complex transitions)</li>
|
|
<li>Other light sources can be synchronized by individually created color transitions.</li>
|
|
</ul>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p><b><a name="WifiLight_Farbkalibrierung"></a>color calibration</b></p>
|
|
WifiLight supports two different types of color calibrations:
|
|
<ul>
|
|
<p>
|
|
<b>Correction of saturated colors</b>
|
|
<p>
|
|
background:
|
|
<p>
|
|
YELLOW, for example, is defined as a mixture of red and green light in equal parts.
|
|
Depending on the LED and control used the green channel may be much more luminous.
|
|
If the red and green LEDs are each fully driven, GREEN predominates in this mixture and the desired YELLOW would get a distinct green tint.
|
|
In this example, no yellow would be generated (corresponding to 60 ° in the <a href="#WifiLight_Farbkreis">"color wheel"</a>) for HSV 60,100,100.
|
|
Instead GREEN would be generated with yellow tinge, perhaps corresponding to an estimated color angle of 80 °.
|
|
The required correction for yellow would therefore minus 20° (60° target - 80° result = -20° correction).
|
|
YELLOW may have to be corrected as to -20 °. Possible values per correction point are +/- 29 °.
|
|
<p>
|
|
procedure:
|
|
<p>
|
|
The correction of the full color is controlled by the attribute "color cast".
|
|
Here 6 (comma separated) values are specified in the range from -29 to 29.
|
|
These values are in accordance with the angle correction for red (0 °), yellow (60 °), green (120 °), cyan (180 °), blue (240 °) and magenta (300 °).
|
|
First, the deviation of the mixed colors (60 ° / 180 ° / 300 °) should be determined as in the above example, and stored in the attribute.
|
|
Following the primary colors (0 ° / 120 ° / 240 °) should be corrected so that the smooth transitions between adjacent pure colors appear as linear as possible.
|
|
This process may need to be repeated iteratively multiple times until the result is harmonious.
|
|
<p>
|
|
<b>White Balance</b>
|
|
<p>
|
|
background:
|
|
<p>
|
|
Some bulbs produce white light by mixing the RGB channels (for example, LW12).
|
|
Depending on the light intensity of the RGB channels of the LED strips used, the result is different.
|
|
One or two colors dominate.
|
|
In addition, there are various types of white light.
|
|
Cold light has a higher proportion of blue.
|
|
In Central Europe mostly warm white light is used for light sources.
|
|
This has a high red and low blue component.
|
|
<p>
|
|
WifiLight offers the possibility for mixed RGB white to adapt the composition.
|
|
The adjustment is carried out via the attribute "white point".
|
|
The attribute expects a value between 0 and 1 (decimal point with) and the three colors are separated by a comma for each of the three RGB channels.
|
|
<p>
|
|
procedure:
|
|
<p>
|
|
A value of "1,1,1" sets all the three channels to 100% each.
|
|
Assuming that the blue component of the white light should be reduced, a value of "1,1,0.5" sets the third channel (BLUE) in white on 0.5 according to 50%.
|
|
Before doing a white balance correction the adjusment of the saturated color should be completed.
|
|
</ul>
|
|
<p><b>Attribute</b></p>
|
|
<ul>
|
|
<li>
|
|
<code>attr <name> <b>colorCast</b> <R,Y,G,C,B,M></code>
|
|
<p>
|
|
<a href="#WifiLight_Farbkalibrierung">color calibration</a> of saturated colors.
|
|
R(ed), Y(ellow), G(reen), C(yan), B(lue), M(agenta) in the range of +/- 29 (degrees)
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>defaultColor</b> <H,S,V></code>
|
|
<p>
|
|
Specify the light color in HSV which is selected at "on". Default is white.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>defaultRamp</b> <0 bis X></code>
|
|
<p>
|
|
Time in seconds. If this attribute is set, a smooth transition is always implicitly generated if no ramp in the set is indicated.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>dimStep</b> <0 bis 100></code>
|
|
<p>
|
|
Value by which the brightness at dim up and dim-down is changed. Default is "7"
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>gamma</b> <X.X></code>
|
|
<p>
|
|
The human eye perceives brightness changes very differently to (logarithmic).
|
|
At low output brightness even a small change in brightness is perceived as very strong and on the other side strong changes are needed at high luminance.
|
|
Therefore, a logarithmic correction of brightness increase of lamps is necessary so that the increase is found to be uniform.
|
|
Some controllers perform this correction internally.
|
|
In other cases it is necessary to store this correction in the module.
|
|
A gamma value of 1.0 (default) results in a linear output values.
|
|
Values less than 1.0 lead to a logarithmic correction.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>whitePoint</b> <R,G,B></code>
|
|
<p>
|
|
<a href="#WifiLight_Farbkalibrierung">color calibration</a> for mixed RGB white light.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b><a href="#readingFnAttributes">readingFnAttributes</a></b></code>
|
|
</li>
|
|
</ul>
|
|
<p><b>Colored device-icon for FhemWeb</b>
|
|
<ul>
|
|
<p>
|
|
To activate a colored icon for <a href="#FHEMWEB">FhemWeb</a> the following attribute must be set:
|
|
<p>
|
|
<li>
|
|
<code>attr <name> <b>devStateIcon</b> {Color_devStateIcon(ReadingsVal($name,"RGB","000000"))}</code>
|
|
</li>
|
|
</ul>
|
|
<p><b>Colorpicker for FhemWeb</b>
|
|
<ul>
|
|
<p>
|
|
In order for the Color Picker can be used in <a href="#FHEMWEB">FhemWeb</a> following attributes need to be set:
|
|
<p>
|
|
<li>
|
|
<code>attr <name> <b>webCmd</b> RGB</code>
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>widgetOverride</b> RGB:colorpicker,RGB</code>
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html
|
|
|
|
=begin html_DE
|
|
|
|
<a name="WifiLight"></a>
|
|
<h3>WifiLight</h3>
|
|
<ul>
|
|
<p>Das Modul steuert eine große Anzahl unterschiedlicher "no name" LED Typen und stellt Ihnen einheitliches Interface zur Verfügung.</p>
|
|
<p>Folgende Typen werden unterstützt:</p>
|
|
|
|
<table>
|
|
<thead align="left">
|
|
<tr>
|
|
<th>
|
|
Leuchtmitteltyp / bridge
|
|
</th>
|
|
<th>
|
|
Type
|
|
</th>
|
|
<th>
|
|
Notiz
|
|
</th>
|
|
<th>
|
|
Signatur im define
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
Milight RGB erste Generation
|
|
</td>
|
|
<td>
|
|
E27, stripe controller
|
|
</td>
|
|
<td>
|
|
*(1,2,a,C)
|
|
</td>
|
|
<td>
|
|
RGB bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight RGBW1 erste Generation
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
*(1,2,a)
|
|
</td>
|
|
<td>
|
|
RGBW1 bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight White
|
|
</td>
|
|
<td>
|
|
E14, E27, GU10, stripe controller, Downlight
|
|
</td>
|
|
<td>
|
|
*(1,2,b,W,nK)
|
|
</td>
|
|
<td>
|
|
White bridge-V2|3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
Milight RGBW2 zweite Generation
|
|
</td>
|
|
<td>
|
|
E14, E27, GU10, stripe controller, Downlight
|
|
</td>
|
|
<td>
|
|
*(2,b,CW,S20)
|
|
</td>
|
|
<td>
|
|
RGBW2 bridge-V3
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12 erste Generation (SSID LEDNet...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12HX (SSID HX...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12HX
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LW12FC (SSID FC...)
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LW12FC
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316 im RGB mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD316
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316 im RGBW mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
*(S20)
|
|
</td>
|
|
<td>
|
|
RGBW LD316
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD316A im RGBW mode
|
|
</td>
|
|
<td>
|
|
E27
|
|
</td>
|
|
<td>
|
|
*(S20)
|
|
</td>
|
|
<td>
|
|
RGBW LD316A
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382 im RGB mode
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382 im RGBW mode
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGBW LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382A (FW 1.0.6) im RGB mode
|
|
</td>
|
|
<td>
|
|
RGB stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGB LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
LD382A (FW 1.0.6) im RGBW mode
|
|
</td>
|
|
<td>
|
|
RGBW stripe controller
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
RGBW LD382
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
SENGLED
|
|
</td>
|
|
<td>
|
|
E27 mit WLAN repeater
|
|
</td>
|
|
<td>
|
|
|
|
</td>
|
|
<td>
|
|
White Sengled
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
SUNRICHER mit RGBW
|
|
</td>
|
|
<td>
|
|
Controller
|
|
</td>
|
|
<td>
|
|
*(!!!)
|
|
</td>
|
|
<td>
|
|
RGBW Sunricher
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>
|
|
<small>
|
|
(1) milght brigbe V2, V3, V4<br />
|
|
(2) milight bridge V3, V4<br />
|
|
(a) eine Gruppe pro bridge<br />
|
|
(b) vier unabhängige Gruppen pro bridge<br />
|
|
(nK) kein Temperatursupport, Kelvin<br />
|
|
(C) rein Color<br />
|
|
(W) rein White<br />
|
|
(CW) rein Color oder White<br />
|
|
(S20) Saturation <20: umschalten white Channel<br />
|
|
(!!!) EXPERIMENTAL<br />
|
|
</p>
|
|
</small>
|
|
<p>
|
|
<table>
|
|
<tr>
|
|
<td>
|
|
<p><b>Farbangaben</b></p>
|
|
<p>Farben können im RGB oder im HSV Farbraum angegeben werden.</p>
|
|
<p>Farbangaben im <a name="WifiLight_Farbraum_HSV"><b>Farbraum "HSV"</b></a> sind vollständig und in der Regel intuitiver als RGB.</p>
|
|
<p><b>H</b> (HUE: 0..360) gibt die Grundfarbe in einem Farbkreis an.
|
|
<ul>
|
|
<li>Rot liegt bei 0°</li>
|
|
<li>Grün bei 120°</li>
|
|
<li>Blau bei 240°</li>
|
|
</ul>
|
|
</p>
|
|
<p><b>S</b> (Saturation/Sättigung: 0..100) steht für die Sättigung der Farbe. Eine Sättigung von 100 bedeutet die Farbe ist "rein" oder komplett gesättigt. Blau zum Beispiel mit 100% Sättigung entspricht RGB #0000FF.</p>
|
|
<p><b>V</b> (Value: 0..100) gibt die Helligkeit an. Ein V von 50 heißt: "halbe Helligkeit".</p>
|
|
</td>
|
|
<td>
|
|
<a name="WifiLight_Farbkreis">
|
|
<svg style="width:450px; height:320px;" viewBox="-100 -30 500 320">
|
|
<linearGradient id="linearColors1" x1="0" y1="0" x2="1" y2="1">
|
|
<stop offset="0%" stop-color="#FF0000"></stop>
|
|
<stop offset="100%" stop-color="#FFFF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors2" x1="0.5" y1="0" x2="0.5" y2="1">
|
|
<stop offset="0%" stop-color="#FFFF00"></stop>
|
|
<stop offset="100%" stop-color="#00FF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors3" x1="1" y1="0" x2="0" y2="1">
|
|
<stop offset="0%" stop-color="#00FF00"></stop>
|
|
<stop offset="100%" stop-color="#00FFFF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors4" x1="1" y1="1" x2="0" y2="0">
|
|
<stop offset="0%" stop-color="#00FFFF"></stop>
|
|
<stop offset="100%" stop-color="#0000FF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors5" x1="0.5" y1="1" x2="0.5" y2="0">
|
|
<stop offset="0%" stop-color="#0000FF"></stop>
|
|
<stop offset="100%" stop-color="#FF00FF"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors6" x1="0" y1="1" x2="1" y2="0">
|
|
<stop offset="0%" stop-color="#FF00FF"></stop>
|
|
<stop offset="100%" stop-color="#FF0000"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors7" x1="152" y1="130" x2="152" y2="35" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#FF0000"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors8" x1="152" y1="130" x2="230" y2="190" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#00FF00"></stop>
|
|
</linearGradient>
|
|
<linearGradient id="linearColors9" x1="152" y1="130" x2="70" y2="190" gradientUnits="userSpaceOnUse">
|
|
<stop offset="0.2" stop-color="#FFFFFF"></stop>
|
|
<stop offset="1" stop-color="#0000FF"></stop>
|
|
</linearGradient>
|
|
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
|
|
<path d="M2,2 L2,11 L10,6 L2,2" style="fill:grey;" />
|
|
</marker>
|
|
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="url(#linearColors1)" stroke-width="20" />
|
|
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="url(#linearColors2)" stroke-width="20" />
|
|
<path d="M253.9230 190 a120 120 0 0 1 -103.9230 60" fill="none" stroke="url(#linearColors3)" stroke-width="20" />
|
|
<path d="M150 250 a120 120 0 0 1 -103.9230 -60" fill="none" stroke="url(#linearColors4)" stroke-width="20" />
|
|
<path d="M46.077 190 a120 120 0 0 1 0 -120" fill="none" stroke="url(#linearColors5)" stroke-width="20" />
|
|
<path d="M46.077 70 a120 120 0 0 1 103.9230 -60" fill="none" stroke="url(#linearColors6)" stroke-width="20" />
|
|
<path d="M150,50 C250,50 250,180 180,200" fill="none" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
|
|
<text class="Label" x="126" y="208">HUE</text>
|
|
<line x1="152" y1="130" x2="152" y2="35" stroke="url(#linearColors7)" stroke-width="4" />
|
|
<line x1="136" y1="120" x2="136" y2="45" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
|
|
<text class="Label" x="96" y="96">SAT</text>
|
|
<line x1="152" y1="130" x2="230" y2="190" stroke="url(#linearColors8)" stroke-width="4" />
|
|
<line x1="152" y1="130" x2="70" y2="190" stroke="url(#linearColors9)" stroke-width="4" />
|
|
<text x="120" y="-10">0° (Rot)</text>
|
|
<text x="270" y="60">60° (Gelb)</text>
|
|
<text x="270" y="220">120° (Grün)</text>
|
|
<text x="110" y="285">180° (Cyan)</text>
|
|
<text x="-60" y="220">240° (Blau)</text>
|
|
<text x="-90" y="60">300° (Magenta)</text>
|
|
</svg>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p><b>Farbangaben: HSV gegenüber RGB</b><p>
|
|
<p>
|
|
Im Normalfall kann eine Farbe im HSV Farbraum genauso wie im RGB Farbraum dargestellt werden.
|
|
<p>
|
|
Farben im HSV Farbraum wirken meist verständlicher.
|
|
Um ein Grün im HSV Farbraum etwas mehr in Richtung CYAN zu bewegen wird einfach der HUE Wert (Winkel) etwas erhöht.
|
|
Im RGB Farbraum ist die gleiche Aufgabe weniger intuitiv durch eine Erhöhung von BLAU zu erreichen.
|
|
<p>
|
|
Unterschiede werden jedoch bei Transitions deutlich.
|
|
Um BLAU langsam auf zu dimmen lauten die HSV Transitions 240,100,0 -> 240,100,100.
|
|
Um von ROT (Helligkeit 0) langsam auf BLAU zu dimmen wird im HSV Farbraum 0,100,0 -> 240,100,100 verwendet.
|
|
Im RGB Farbraum (#000000 -> #0000FF) kann nicht zwischen den beiden Varianten unterschieden werden.
|
|
Hier würde (richtiger weise, vermutlich jedoch anders als beabsichtigt) in beiden Fällen ein Weiß (Helligkeit 0) als Startwert erscheinen.
|
|
</p>
|
|
|
|
<p><b>Define</b></p>
|
|
<ul>
|
|
<li>
|
|
<p><code>define <name> WifiLight <Leuchtmitteltyp> <bridgetyp>:<IP|FQDN></code></p>
|
|
<p>
|
|
<i><u>Beispiele</u></i>
|
|
<ul>
|
|
<p>
|
|
<i>definiert einen milight RGBW2 Leuchtmittel (Bulb oder LED stripe controller) an einer milight bridge Version 3 oder 4.
|
|
Die LED wird den maximal 4 verfügbaren Gruppen pro bridge in der Reihenfolge der Definition zugeordnet:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGBW2 bridge-V3:192.168.178.142</code>
|
|
</ul>
|
|
<ul>
|
|
<p>
|
|
<i>definiert einen LD382A Controller mit RGBW Stripe:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGBW LD382A:192.168.178.142</code>
|
|
</ul>
|
|
<ul>
|
|
<p>
|
|
<i>definiert einen LD382A Controller mit RGB Stripe:</i>
|
|
<br/>
|
|
<code>define wz.licht.decke WifiLight RGB LD382A:192.168.178.142</code>
|
|
</ul>
|
|
<p>WifiLight verfügt über eine <a href="#WifiLight_Farbkalibrierung">"Farbkalibrierung"</a>. Sinnvollerweise sollte nach einem Leuchtmitteltausch oder einem define eine Kalibrierung vorgenommen werden.</p>
|
|
</ul>
|
|
</li>
|
|
<p><b>Set</b></p>
|
|
<ul>
|
|
<li>
|
|
<p><code>set <name> <b>on</b> [ramp]</code></p>
|
|
<p>Schaltet das device ein. Dabei wird entweder 100% Weiß oder die im Attribut "defaultColor" definierte Farbe gewählt.
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>off</b> [ramp]</code></p>
|
|
<p>Schaltet das device aus.
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dimup</b></code></p>
|
|
<p>Erhöht die Helligkeit um einen festen Betrag. Dabei wird der im Attribut "dimStep" definierte Wert oder der Default "7" angewendet.<br>Dieser Befehl eignet sich besonders um die Helligkeit über einen Wandschalter oder eine Fernbedienung zu erhöhen.
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>keine</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dimdown</b></code></p>
|
|
<p>Verringert die Helligkeit um einen festen Betrag. Dabei wird der im Attribut "dimStep" definierte Wert oder der Default "7" angewendet.<br>Dieser Befehl eignet sich besonders um die Helligkeit über einen Wandschalter oder eine Fernbedienung zu verringern
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>keine</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>dim</b> level [ramp] [q]</code></p>
|
|
<p>Setzt die Helligkeit auf den angegebenen level (0..100).<br>Dieser Befehl behält außerdem die eingestellte Farbe auch bei "dim 0" (ausgeschaltet) und nachfolgendem "dim xx" (eingeschaltet) bei. Daher stellt er eine alternative Form zu "off" / "on" dar. Letzteres würde immer die "defaultColor" wählen.
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>q</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>HSV</b> H,S,V [ramp] [s|l|q] [event]</code></p>
|
|
<p>Setzt die Farbe im <a href="#WifiLight_Farbraum_HSV">HSV Farbraum</a>. Wenn die ramp (als Zeit in Sekunden) angegeben ist, berechnet das modul einen weichen Farbübergang von der aktuellen Farbe zur neu gesetzten.
|
|
<ul><i>Beispiel, setzt ein gesättigtes Blau mit halber Helligkeit:</i><br /><code>set wz.licht.decke HSV 240,100,50</code></ul>
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>s l q event</li>
|
|
</ul>
|
|
</p>
|
|
</li>
|
|
<li>
|
|
<p><code>set <name> <b>RGB</b> RRGGBB [ramp] [l|s|q] [event]</code></p>
|
|
<p>Setzt die Farbe im RGB Farbraum.
|
|
<p>Erweiterte Parameter:
|
|
<ul>
|
|
<li>ramp</li>
|
|
</ul>
|
|
</p>
|
|
<p>Flags:
|
|
<ul>
|
|
<li>s l q event</li>
|
|
</ul>
|
|
</p>
|
|
</ul>
|
|
</li>
|
|
<p><b>Bedeutung der Flags</b></p>
|
|
Bestimmte Befehle (set) können mit speziellen Flags versehen werden.
|
|
<p>
|
|
<ul>
|
|
<li>ramp:
|
|
<ul>
|
|
Zeit in Sekunden für einen weichen Farb- oder Helligkeitsübergang. Der weiche Übergang startet bei der aktuell sichtbaren Farbe und wird zur angegeben berechnet.
|
|
</ul>
|
|
</li>
|
|
<li>s:
|
|
<ul>
|
|
(short, default). Ein weicher Übergang zu einer anderen Farbe wird im <a href="#WifiLight_Farbkreis">"Farbkreis"</a> auf dem kürzesten Weg durchgeführt.</br>
|
|
Eine Transition von ROT nach GRÜN führt auf dem kürzesten Weg über GELB.
|
|
</ul>
|
|
</li>
|
|
<li>l:
|
|
<ul>
|
|
(long). Ein weicher Übergang zu einer anderen Farbe wird im <a href="#WifiLight_Farbkreis">"Farbkreis"</a> auf dem "langen" Weg durchgeführt.</br>
|
|
Eine Transition von ROT nach GRÜN führt dann über MAGENTA, BLAU, und CYAN.
|
|
</ul>
|
|
</li>
|
|
<li>q:
|
|
<ul>
|
|
(queue). Kommandos mit diesem Flag werden in einer internen Warteschlange zwischengespeichert und erst ausgeführt nachdem die aktuell laufenden weichen Übergänge
|
|
abgearbeitet wurden. Kommandos ohne das Flag werden sofort abgearbeitet. Dabei werden alle laufenden Übergänge sofort abgebrochen und die Warteschlange wird gelöscht.
|
|
</ul>
|
|
</li>
|
|
<li>event:
|
|
<ul>
|
|
Beliebige Bezeichnung ([A-Za-z_0-9])
|
|
<p>
|
|
WifiLight erzeugt bei Verwendung dieses Flags im Verlauf weicher Übergange zu einer anderen Farbe Nachrichten (events) in der Form:
|
|
<p>
|
|
<code>WifiLight <NAME> programm: <EVENT> <XX></code>.
|
|
<p>
|
|
<EVENT> entspricht dem Namen so wie im Flag angegeben.<br/>
|
|
<XX> ist der prozentuale Fortschritt des Übergangs.<br/>
|
|
<p>
|
|
Je nach Gesamtdauer des Übergangs werden die Werte von 0 bis 100 nicht komplett durchlaufen wobei jedoch für 0% und 100% immer ein event garantiert ist. Auf diese events kann dann innerhalb von notify oder DOIF reagiert werden um zum Beispiel:
|
|
<ul>
|
|
<li>die Lautstärke eines Radios anzupassen wenn eine LED morgens langsam hochgedimmt wird</li>
|
|
<li>ein Farbübergang kann in einem notify neu gestartet werden wenn er komplett ist (loop)</li>
|
|
<li>andere Leuchtmittel können mit erstellten Farbübergängen synchronisiert werden</li>
|
|
</ul>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p><b><a name="WifiLight_Farbkalibrierung"></a>Farbkalibrierung</b></p>
|
|
WifiLight unterstützt zwei unterschiedliche Formen der Farbkalibrierungen:
|
|
<ul>
|
|
<p>
|
|
<b>Korrektur gesättigter Farben</b>
|
|
<p>
|
|
Hintergrund:
|
|
<p>
|
|
GELB, zum Beispiel, ist definiert als Mischung aus ROTEM und GRÜNEM Licht zu gleichen Teilen.
|
|
Je nach verwendeter LED und Ansteuerung ist der GRÜNE Kanal nun möglicherweise viel leuchtstärker.
|
|
Wenn jetzt also die ROTE und GRÜNE LED jeweils voll angesteuert werden überwiegt GRÜN in dieser Mischung und das gewünschte GELB bekäme einen deutlichen Grünstich.
|
|
In diesem Beispiel würde jetzt für HSV 60,100,100 kein Gelb (entsprechend 60° im <a href="#WifiLight_Farbkreis">"Farbkreis"</a>) erzeugt.
|
|
Stattdessen würde GRÜN mit GELBSTICH erzeugt das vielleicht einem geschätzten Farbwinkel von 80° entspricht.
|
|
Die erforderliche Korrektur für GELB würde also minus 20° betragen (60° SOLL - 80° IST = -20° Korrektur).
|
|
GELB müsste als um -20° korrigiert werden. Mögliche Werte pro Korrektur-Punkt sind +/- 29°.
|
|
<p>
|
|
Vorgehen:
|
|
<p>
|
|
Die Korrektur der Vollfarben wird über das Attribut "colorCast" gesteuert. Dabei werden 6 (Komma getrennte) Werte im Bereich -29 bis 29 angegeben.
|
|
Diese Werte stehen entsprechen der Winkelkorrektur für ROT (0°), GELB (60°), GRÜN (120°), CYAN (180°), BLAU (240°) und MAGENTA (300°).
|
|
Zuerst sollte die Abweichung für 60°/180°/300° (die Mischfarben) so wie in obigem Beispiel ermittelt und im Attribut hinterlegt werden.
|
|
Im Anschluss sollten die Primärfarben (0°/120°/240°) so korrigiert werden das die weichen Übergänge zwischen benachbarten reinen Farben möglichst linear erscheinen.
|
|
Dieser Vorgang muss eventuell iterativ mehrfach wiederholt werden bis das Ergebniss stimmig ist.
|
|
<p>
|
|
<b>Weißabgleich</b>
|
|
<p>
|
|
Hintergrund:
|
|
<p>
|
|
Einige Leuchtmittel erzeugen weißes Licht durch Mischung der RGB Kanäle (zum Beispiel LW12).
|
|
Je nach Leuchtstärke der RGB Kanäle der verwendeten LED Streifen unterscheidet sich das Ergebnis und eine oder zwei Farben dominieren.
|
|
Zusätzlich gibt es verschiedene Formen weißen Lichtes. Kaltes Licht hat einen höheren Blauanteil.
|
|
Dagegen wird in Mitteleuropa für Leuchtmittel meist warm-weiß verwendet welches einen hohen ROT- und geringen BLAU Anteil hat.
|
|
<p>
|
|
WifiLight bietet die Möglichkeit bei RGB gemischtem Weiß die Zusammensetzung anzupassen. Die Anpassung erfolgt über das Attribut "whitePoint".
|
|
Dieses erwartet für jeden der drei RGB Kanäle einen Wert zwischen 0 und 1 (ein Komma wird als Punkt angegeben). Die drei Werte werden mit einem normalen Komma getrennt.
|
|
<p>
|
|
Vorgehen:
|
|
<p>
|
|
Eine Angabe von "1,1,1" setzt alle die drei Kanäle auf jeweils 100%. Angenommen der BLAU Anteil des weißen Lichtes soll nun verringert werden.
|
|
Ein Wert von "1,1,0.5" setzt den dritten Kanal (BLAU) bei Weiß auf 0.5 entsprechend 50%. Vor einem Weißabgleich sollte die Korrektur der Vollfarben abgeschlossen sein.
|
|
</ul>
|
|
<p><b>Attribute</b></p>
|
|
<ul>
|
|
<li>
|
|
<code>attr <name> <b>colorCast</b> <R,Y,G,C,B,M></code>
|
|
<p>
|
|
<a href="#WifiLight_Farbkalibrierung">Farbkalibrierung</a> der voll gesättigten Farben.
|
|
R(ed), Y(ellow), G(reen), C(yan), B(lue), M(agenta) im Bereich +/- 29
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>defaultColor</b> <H,S,V></code>
|
|
<p>
|
|
HSV Angabe der Lichtfarbe die bei "on" gewählt wird. Default ist Weiß.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>defaultRamp</b> <0 bis X></code>
|
|
<p>
|
|
Zeit in Sekunden. Wenn dieses Attribut gesetzt ist wird implizit immer ein weicher Übergang erzeugt wenn keine Ramp im set angegeben ist.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>dimStep</b> <0 bis 100></code>
|
|
<p>
|
|
Wert um den die Helligkeit bei dimUp und dimDown verändert wird. Default 7.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>gamma</b> <X.X></code>
|
|
<p>
|
|
Das menschliche Auge nimmt Helligkeitsänderungen sehr unterschiedlich wahr (logarithmisch).
|
|
Bei geringer Ausgangshelligkeit wird schon eine kleine Helligkeitsänderung als sehr stark empfunden und auf der anderen Seite sind bei großer Helligkeit starke Änderungen notwendig.
|
|
Daher ist eine logarithmische Korrektur des Helligkeitsanstiegs der Leuchtmittel erforderlich damit der Anstieg als gleichmäßig empfunden wird.
|
|
Einige controller führen diese Korrektur intern durch. In anderen Fällen ist es notwendig diese Korrektur im Modul zu hinterlegen.
|
|
Ein gamma Wert von 1.0 (default) führt zu einer linearen Ausgabe der Werte. Werte kleiner als 1.0 führen zu einer logarithmischem Korrektur.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>whitePoint</b> <R,G,B></code>
|
|
<p>
|
|
<a href="#WifiLight_Farbkalibrierung">Farbkalibrierung</a> für RGB gemischtes weißes Licht.
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b><a href="#readingFnAttributes">readingFnAttributes</a></b></code>
|
|
</li>
|
|
</ul>
|
|
<p><b>Farbiges Icon für FhemWeb</b>
|
|
<ul>
|
|
<p>
|
|
Um ein farbiges Icon für <a href="#FHEMWEB">FhemWeb</a> zu aktivieren muss das folgende Attribut gesetzt sein:
|
|
<p>
|
|
<li>
|
|
<code>attr <name> <b>devStateIcon</b> {Color_devStateIcon(ReadingsVal($name,"RGB","000000"))}</code>
|
|
</li>
|
|
</ul>
|
|
<p><b>Colorpicker für FhemWeb</b>
|
|
<ul>
|
|
<p>
|
|
Um den Color-Picker für <a href="#FHEMWEB">FhemWeb</a> zu aktivieren müssen folgende Attribute gesetzt werden:
|
|
<p>
|
|
<li>
|
|
<code>attr <name> <b>webCmd</b> RGB</code>
|
|
</li>
|
|
<li>
|
|
<code>attr <name> <b>widgetOverride</b> RGB:colorpicker,RGB</code>
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html_DE
|