public static RgbColor ToRgb(this HsbkColor hsb)
        {
            double r, g, b;
            var    h = hsb.Hue / 360d;

            if (Math.Abs(hsb.Saturation) < 0.001)
            {
                r = g = b = hsb.Brightness * 255d; // achromatic
            }
            else
            {
                var q = hsb.Brightness < 0.5
                    ? hsb.Brightness * (1 + hsb.Saturation)
                    : hsb.Brightness + hsb.Saturation - hsb.Brightness * hsb.Saturation;
                var p = 2 * hsb.Brightness - q;
                r = HueToRgb(p, q, h + 1d / 3d) * 255d;
                g = HueToRgb(p, q, h) * 255d;
                b = HueToRgb(p, q, h - 1d / 3d) * 255d;
            }

            return(new RgbColor
            {
                Red = (byte)r,
                Green = (byte)g,
                Blue = (byte)b
            });
        }
        public LifxMessageSetColor(HsbkColor color, uint durationInMs) : base(102)
        {
            Address.ResponseRequired = true;

            Payload = new LifxMessageSetColorPayload
            {
                Color        = color,
                DurationInMs = durationInMs
            };
        }
        public LifxMessageState(byte[] payload) : base(107)
        {
            Color = new HsbkColor();
            Color.Deserialize(payload);

            var power = BitConverter.ToUInt16(payload, 10);

            IsPower = power == ushort.MaxValue;

            var label = Encoding.UTF8.GetString(payload, 12, 32);

            Label = label.Trim('\0');
        }
        private async Task ExecuteLocalAction(LifxDevice device, string action, int seconds, double brightness, string color)
        {
            var light = _localClient.Lights.SingleOrDefault(l => l.Id.Equals(device.Id));
            var b = (ushort)(brightness * 65535);

            if (light == null)
            {
                return;
            }

            switch (action.ToLowerInvariant())
            {
                case "switch on":
                    if (seconds == 0)
                    {
                        await _localClient.SetDevicePowerStateAsync(light, true);
                    }
                    else if (seconds > 0)
                    {
                        await _localClient.SetLightPowerAsync(light, TimeSpan.FromSeconds(seconds), true);
                    }
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                    break;
                case "switch off":
                    if (seconds == 0)
                    {
                        await _localClient.SetDevicePowerStateAsync(light, false);
                    }
                    else if (seconds > 0)
                    {
                        await _localClient.SetLightPowerAsync(light, TimeSpan.FromSeconds(seconds), false);
                    }
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", false));
                    break;
                case "change color":
                    var rgb = color.ParseRgb();
                    var hsb = rgb.ToHsbk();
                    var hue = (ushort)(hsb.Hue * 65535 / 360);
                    var saturation = (ushort) (hsb.Saturation*65535);
                    b = (ushort) (hsb.Brightness*65535);
                    ushort kelvin = 4500;
                    await _localClient.SetColorAsync(light, hue, saturation, b, kelvin, TimeSpan.FromSeconds(seconds));
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "Color", rgb.ToString()));
                    break;
                case "change brightness":
                    var hsbk = light.Color;
                    if (hsbk == null)
                    {
                        hsbk = new HsbkColor();
                        hsbk.Hue = 0;
                        hsbk.Saturation = 0;
                        hsbk.Kelvin = 4500;
                    }
                    hue = (ushort) (hsbk.Hue*65535/360);
                    saturation = (ushort) (hsbk.Saturation*65535);
                    await _localClient.SetColorAsync(light, hue, saturation, b, (ushort)hsbk.Kelvin, TimeSpan.FromSeconds(seconds));
                    var db = Math.Round(brightness, 2);
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "Brightness", db));
                    _messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                    break;
                default:
                    return;
            }
        }
        public async Task SetColorAsync(LifxLocalLight bulb, HsbkColor color, TimeSpan transitionDuration)
        {
            var duration = (uint)Math.Max(0, Math.Min(uint.MaxValue, transitionDuration.TotalMilliseconds));

            await SendAsync(bulb, new LifxMessageSetColor(color, duration));
        }
        private async Task ExecuteLocalAction(LifxDevice device, string action, int seconds, double brightness, string color)
        {
            var light = _localClient.Lights.SingleOrDefault(l => l.Id.Equals(device.Id));
            var b     = (ushort)(brightness * 65535);

            if (light == null)
            {
                return;
            }

            var hsbk = light.Color;

            if (hsbk == null)
            {
                hsbk = new HsbkColor
                {
                    Kelvin = 4500
                };
            }

            switch (action.ToLowerInvariant())
            {
            case "switch on":
                if (seconds == 0)
                {
                    await _localClient.SetPowerAsync(light, true);
                }
                else if (seconds > 0)
                {
                    await _localClient.SetPowerAsync(light, TimeSpan.FromSeconds(seconds), true);
                }
                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                break;

            case "switch off":
                if (seconds == 0)
                {
                    await _localClient.SetPowerAsync(light, false);
                }
                else if (seconds > 0)
                {
                    await _localClient.SetPowerAsync(light, TimeSpan.FromSeconds(seconds), false);
                }
                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", false));
                break;

            case "change color":
                var rgb = color.ParseRgb();
                var hsb = rgb.ToHsbk();

                hsbk.Hue        = hsb.Hue;
                hsbk.Saturation = hsb.Saturation;
                hsbk.Brightness = hsb.Brightness;

                await _localClient.SetColorAsync(light, hsbk, TimeSpan.FromSeconds(seconds));

                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "Color", rgb.ToString()));
                break;

            case "change brightness":
                hsbk.Brightness = brightness;

                await _localClient.SetColorAsync(light, hsbk, TimeSpan.FromSeconds(seconds));

                //var db = Math.Round(brightness, 2);
                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "Brightness", db));
                //_messageQueue.Publish(new UpdateVariableMessage(Name, device.Id, "IsOn", true));
                break;

            default:
                return;
            }
        }
        private void ProcessVariables(LifxResponse msg, LifxLocalLight light)
        {
            var stateLabelResponse = msg as StateLabelResponse;
            var lightStateResponse = msg as LightStateResponse;
            var lightPowerResponse = msg as LightPowerResponse;

            if (stateLabelResponse != null)
            {
                light.Name = stateLabelResponse.Label;
                VariableChanged?.Invoke(light, Tuple.Create(light, "Name", (object)stateLabelResponse.Label));
            }
            else if (lightStateResponse != null)
            {
                var brightness = lightStateResponse.Brightness/65535d;
                var saturation = lightStateResponse.Saturation/65535d;
                var kelvin = lightStateResponse.Kelvin;
                double hue = lightStateResponse.Hue;

                var color = new HsbkColor
                {
                    Hue = hue,
                    Saturation = saturation,
                    Brightness = brightness,
                    Kelvin = kelvin
                };
                
                var hexColor = color.ToRgb().ToString();

                light.Name = lightStateResponse.Label;
                light.Color = color;
                VariableChanged?.Invoke(light, Tuple.Create(light, "Color", (object)hexColor));
                VariableChanged?.Invoke(light, Tuple.Create(light, "Brightness", (object)Math.Round(brightness, 2)));
                VariableChanged?.Invoke(light, Tuple.Create(light, "Name", (object)lightStateResponse.Label));
                VariableChanged?.Invoke(light, Tuple.Create(light, "IsOn", (object)lightStateResponse.IsOn));
            }
            else if (lightPowerResponse != null)
            {
                VariableChanged?.Invoke(light, Tuple.Create(light, "IsOn", (object)lightPowerResponse.IsOn));
            }
        }