Exemple #1
0
        private static void GenerateRandomEffectSettings(out RGBColor hexColor, out IteratorEffectMode iteratorMode, out IteratorEffectMode iteratorSecondaryMode)
        {
            Random r = new Random();

            hexColor = RGBColor.Random(r);
            while (hexColor.R < 0.15 && hexColor.G < 0.15 && hexColor.B < 0.15)
            {
                hexColor = RGBColor.Random(r);
            }

            Array values = Enum.GetValues(typeof(IteratorEffectMode));

            iteratorMode          = (IteratorEffectMode)values.GetValue(r.Next(values.Length));
            iteratorSecondaryMode = (IteratorEffectMode)values.GetValue(r.Next(values.Length));

            //Bounce and Single are no fun for random mode
            if (iteratorMode == IteratorEffectMode.Bounce || iteratorMode == IteratorEffectMode.Single)
            {
                iteratorMode = IteratorEffectMode.Cycle;
            }
            else if (iteratorMode == IteratorEffectMode.RandomOrdered) //RandomOrdered only runs once
            {
                iteratorMode = IteratorEffectMode.Random;
            }
        }
Exemple #2
0
        public static Task SetRandomColor(this IEnumerable <StreamingLight> group, IteratorEffectMode mode = IteratorEffectMode.Cycle, Ref <TimeSpan?> waitTime = null, Ref <TimeSpan?> transitionTime = null, TimeSpan?duration = null, CancellationToken cancellationToken = new CancellationToken())
        {
            if (waitTime == null)
            {
                waitTime = TimeSpan.FromMilliseconds(50);
            }
            if (transitionTime == null)
            {
                transitionTime = TimeSpan.FromMilliseconds(0);
            }

            return(group.IteratorEffect(async(current, t) => {
                var r = new Random();
                var color = new RGBColor(r.NextDouble(), r.NextDouble(), r.NextDouble());
                current.SetState(color, 1, transitionTime.Value.Value);
            }, mode, waitTime, duration, cancellationToken));
        }
        /// <summary>
        /// Does not wait for the previous flash to end
        /// NOTE: Can not be used with mode All or AllIndividual
        /// </summary>
        /// <param name="group"></param>
        /// <param name="color"></param>
        /// <param name="mode"></param>
        /// <param name="waitTime"></param>
        /// <param name="onTime"></param>
        /// <param name="transitionTimeOn"></param>
        /// <param name="transitionTimeOff"></param>
        /// <param name="duration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static Task FlashQuick(this IEnumerable <IEnumerable <EntertainmentLight> > group, CancellationToken cancellationToken, RGBColor?color, IteratorEffectMode mode = IteratorEffectMode.Cycle, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All, Func <TimeSpan> waitTime = null, Func <TimeSpan> onTime = null, Func <TimeSpan> transitionTimeOn = null, Func <TimeSpan> transitionTimeOff = null, TimeSpan?duration = null)
        {
            if (!color.HasValue)
            {
                color = RGBColor.Random();
            }

            if (mode == IteratorEffectMode.All || mode == IteratorEffectMode.AllIndividual)
            {
                return(group.Flash(cancellationToken, color.Value, mode, secondaryIteratorMode, waitTime, onTime, transitionTimeOn, transitionTimeOff, true, duration));
            }
            else
            {
                if (waitTime == null)
                {
                    waitTime = () => TimeSpan.FromMilliseconds(50);
                }
                if (onTime == null)
                {
                    onTime = waitTime;
                }
                if (transitionTimeOn == null)
                {
                    transitionTimeOn = () => TimeSpan.FromMilliseconds(0);
                }
                if (transitionTimeOff == null)
                {
                    transitionTimeOff = () => TimeSpan.FromMilliseconds(0);
                }

                Func <TimeSpan> actualWaitTime = () => onTime() + transitionTimeOn();

                return(group.IteratorEffect(cancellationToken, async(current, ct, t) =>
                {
                    current.SetState(ct, color, 1, transitionTimeOn());
                    Task.Run(async() =>
                    {
                        await Task.Delay(onTime() + transitionTimeOn(), ct).ConfigureAwait(false);
                        current.SetBrightness(ct, 0, transitionTimeOff());
                    }, ct);
                }, mode, secondaryIteratorMode, actualWaitTime, duration));
            }
        }
        public static Task SetRandomColor(this IEnumerable <IEnumerable <EntertainmentLight> > group, CancellationToken cancellationToken, IteratorEffectMode mode = IteratorEffectMode.Cycle, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All, Func <TimeSpan> waitTime = null, Func <TimeSpan> transitionTime = null, TimeSpan?duration = null)
        {
            if (waitTime == null)
            {
                waitTime = () => TimeSpan.FromMilliseconds(50);
            }
            if (transitionTime == null)
            {
                transitionTime = () => TimeSpan.FromMilliseconds(0);
            }

            return(group.IteratorEffect(cancellationToken, async(current, ct, t) =>
            {
                var color = RGBColor.Random();

                current.SetState(ct, color, 1, transitionTime());
            }, mode, secondaryIteratorMode, waitTime, duration));
        }
        public static Task SetColor(this IEnumerable <IEnumerable <EntertainmentLight> > group, CancellationToken cancellationToken, RGBColor color, IteratorEffectMode mode = IteratorEffectMode.Cycle, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All, Func <TimeSpan> waitTime = null, Func <TimeSpan> transitionTime = null, TimeSpan?duration = null)
        {
            var list = new List <RGBColor>()
            {
                color
            };

            return(SetRandomColorFromList(group, cancellationToken, list, mode, secondaryIteratorMode, waitTime, transitionTime, duration));
        }
Exemple #6
0
        private static void StartEffect(CancellationToken ctsToken, TypeInfo selectedEffect, IEnumerable <IEnumerable <EntertainmentLight> > group, string groupName, Func <TimeSpan> waitTime, RGBColor?color, IteratorEffectMode iteratorMode = IteratorEffectMode.All, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All)
        {
            MethodInfo?methodInfo = selectedEffect.GetMethod("Start");

            if (methodInfo == null)
            {
                return;
            }

            //get group
            if (group == null)
            {
                group = GroupService.GetRandomGroup();
            }

            object[] parametersArray = new object[] { group, waitTime, color, iteratorMode, secondaryIteratorMode, ctsToken };


            object?classInstance = Activator.CreateInstance(selectedEffect, null);

            methodInfo.Invoke(classInstance, parametersArray);

            var hub = (IHubContext <StatusHub>)Startup.ServiceProvider.GetService(typeof(IHubContext <StatusHub>));

            hub.Clients.All.SendAsync("StartingEffect", $"Starting: {selectedEffect.Name} {groupName}, {iteratorMode}-{secondaryIteratorMode} {color?.ToHex()}",
                                      new EffectLogMsg()
            {
                EffectType            = "group",
                Name                  = selectedEffect.Name,
                RGBColor              = color?.ToHex(),
                Group                 = groupName,
                IteratorMode          = iteratorMode.ToString(),
                SecondaryIteratorMode = secondaryIteratorMode.ToString(),
            });
        }
Exemple #7
0
        public static void StartEffect(string typeName, string colorHex, string?group = null, IteratorEffectMode iteratorMode = IteratorEffectMode.All, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All)
        {
            var hub = (IHubContext <StatusHub>)Startup.ServiceProvider.GetService(typeof(IHubContext <StatusHub>));

            var all      = GetEffectTypes();
            var allGroup = GetGroupEffectTypes();

            var effectType      = all.Where(x => x.Name == typeName).FirstOrDefault();
            var groupEffectType = allGroup.Where(x => x.Name == typeName).FirstOrDefault();

            bool isGroupEffect  = groupEffectType != null && !string.IsNullOrEmpty(group);
            var  selectedEffect = isGroupEffect ? groupEffectType : effectType;

            if (selectedEffect != null)
            {
                var hueEffectAtt = selectedEffect.GetCustomAttribute <HueEffectAttribute>();
                if (hueEffectAtt == null)
                {
                    return;
                }

                var isBaseLayer = hueEffectAtt.IsBaseEffect && iteratorMode != IteratorEffectMode.Single && iteratorMode != IteratorEffectMode.RandomOrdered;
                var layer       = GetLayer(isBaseLayer);

                if (layerInfo.ContainsKey(layer))
                {
                    //Cancel currently running job
                    layerInfo[layer].CancellationTokenSource?.Cancel();
                }

                CancellationTokenSource cts = new CancellationTokenSource();
                layerInfo[layer] = new RunningEffectInfo()
                {
                    Name = hueEffectAtt.Name, CancellationTokenSource = cts
                };

                Func <TimeSpan> waitTime = () => StreamingSetup.WaitTime;
                RGBColor?       color    = null;
                if (!string.IsNullOrEmpty(colorHex))
                {
                    color = new RGBColor(colorHex);
                }


                if (isGroupEffect)
                {
                    //get group
                    var selectedGroup = GroupService.GetAll(layer).Where(x => x.Name == group).Select(x => x.Lights).FirstOrDefault();

                    StartEffect(cts.Token, selectedEffect, selectedGroup.SelectMany(x => x), group, waitTime, color, iteratorMode, secondaryIteratorMode);
                }
                else
                {
                    StartEffect(cts.Token, selectedEffect, layer, waitTime, color);
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// Does not wait for the previous flash to end
        /// NOTE: Can not be used with mode All or AllIndividual
        /// </summary>
        /// <param name="group"></param>
        /// <param name="color"></param>
        /// <param name="mode"></param>
        /// <param name="waitTime"></param>
        /// <param name="onTime"></param>
        /// <param name="transitionTimeOn"></param>
        /// <param name="transitionTimeOff"></param>
        /// <param name="duration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static Task FlashQuick(this IEnumerable <StreamingLight> group, RGBColor?color, IteratorEffectMode mode = IteratorEffectMode.Cycle, Ref <TimeSpan?> waitTime = null, Ref <TimeSpan?> onTime = null, Ref <TimeSpan?> transitionTimeOn = null, Ref <TimeSpan?> transitionTimeOff = null, TimeSpan?duration = null, CancellationToken cancellationToken = new CancellationToken())
        {
            if (!color.HasValue)
            {
                var r = new Random();
                color = new RGBColor(r.NextDouble(), r.NextDouble(), r.NextDouble());
            }

            if (mode == IteratorEffectMode.All || mode == IteratorEffectMode.AllIndividual)
            {
                return(group.Flash(color.Value, mode, waitTime, onTime, transitionTimeOn, transitionTimeOff, duration, cancellationToken));
            }
            else
            {
                if (waitTime == null)
                {
                    waitTime = TimeSpan.FromMilliseconds(50);
                }
                if (onTime == null)
                {
                    onTime = waitTime;
                }
                if (transitionTimeOn == null)
                {
                    transitionTimeOn = TimeSpan.FromMilliseconds(0);
                }
                if (transitionTimeOff == null)
                {
                    transitionTimeOff = TimeSpan.FromMilliseconds(0);
                }

                Ref <TimeSpan?> actualWaitTime = onTime.Value + transitionTimeOn.Value;

                return(group.IteratorEffect(async(current, t) =>
                {
                    actualWaitTime.Value = onTime.Value.Value + transitionTimeOn.Value.Value;

                    current.SetState(color, 1, transitionTimeOn.Value.Value);
                    Task.Run(async() =>
                    {
                        await Task.Delay(onTime.Value.Value + transitionTimeOn.Value.Value);
                        current.SetBrightness(0, transitionTimeOff.Value.Value);
                    }, cancellationToken);
                }, mode, actualWaitTime, duration, cancellationToken));
            }
        }
Exemple #9
0
        public static Task Flash(this IEnumerable <IEnumerable <EntertainmentLight> > group, CancellationToken cancellationToken, RGBColor?color, IteratorEffectMode mode = IteratorEffectMode.Cycle, IteratorEffectMode secondaryIteratorMode = IteratorEffectMode.All, Ref <TimeSpan?> waitTime = null, Ref <TimeSpan?> onTime = null, Ref <TimeSpan?> transitionTimeOn = null, Ref <TimeSpan?> transitionTimeOff = null, bool waitTillFinished = true, TimeSpan?duration = null)
        {
            if (!color.HasValue)
            {
                var r = new Random();
                color = new RGBColor(r.NextDouble(), r.NextDouble(), r.NextDouble());
            }

            if (waitTime == null)
            {
                waitTime = TimeSpan.FromMilliseconds(50);
            }
            if (onTime == null)
            {
                onTime = waitTime;
            }
            if (transitionTimeOn == null)
            {
                transitionTimeOn = TimeSpan.FromMilliseconds(0);
            }
            if (transitionTimeOff == null)
            {
                transitionTimeOff = TimeSpan.FromMilliseconds(0);
            }

            Ref <TimeSpan?> actualWaitTime = waitTime.Value + onTime.Value + transitionTimeOn.Value + transitionTimeOff.Value;

            if (!waitTillFinished)
            {
                actualWaitTime = waitTime.Value;
            }

            return(group.IteratorEffect(cancellationToken, async(current, ct, t) =>
            {
                if (!waitTillFinished)
                {
                    actualWaitTime.Value = waitTime.Value;
                }
                else
                {
                    actualWaitTime.Value = waitTime.Value.Value + onTime.Value.Value + transitionTimeOn.Value.Value + transitionTimeOff.Value.Value;
                }

                current.SetState(ct, color, 1, transitionTimeOn.Value.Value);
                Task.Run(async() =>
                {
                    await Task.Delay(onTime.Value.Value + transitionTimeOn.Value.Value, ct).ConfigureAwait(false);
                    current.SetBrightness(ct, 0, transitionTimeOff.Value.Value);
                }, ct);
            }, mode, secondaryIteratorMode, actualWaitTime, duration));
        }
Exemple #10
0
        public static Task SetRandomColorFromList(this IEnumerable <StreamingLight> group, List <RGBColor> colors, IteratorEffectMode mode = IteratorEffectMode.Cycle, Ref <TimeSpan?> waitTime = null, Ref <TimeSpan?> transitionTime = null, TimeSpan?duration = null, CancellationToken cancellationToken = new CancellationToken())
        {
            if (waitTime == null)
            {
                waitTime = TimeSpan.FromMilliseconds(50);
            }
            if (transitionTime == null)
            {
                transitionTime = TimeSpan.FromMilliseconds(0);
            }

            return(group.IteratorEffect(async(current, t) => {
                var color = colors.OrderBy(x => new Guid()).First();
                current.SetState(color, 1, transitionTime.Value.Value);
            }, mode, waitTime, duration, cancellationToken));
        }
Exemple #11
0
        /// <summary>
        /// Apply the effectFunction repeatedly to a group of lights
        /// </summary>
        /// <param name="group"></param>
        /// <param name="effectFunction"></param>
        /// <param name="mode"></param>
        /// <param name="waitTime"></param>
        /// <param name="duration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task IteratorEffect(this IEnumerable <EntertainmentLight> group, CancellationToken cancellationToken, IteratorEffectFunc effectFunction, IteratorEffectMode mode, Func <TimeSpan> waitTime, TimeSpan?duration = null, int maxIterations = int.MaxValue)
        {
            if (waitTime == null)
            {
                waitTime = () => TimeSpan.FromSeconds(1);
            }
            if (duration == null)
            {
                duration = TimeSpan.MaxValue;
            }

            bool keepGoing = true;
            var  lights    = group.ToList();
            bool reverse   = false;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            int i = 0;

            while (keepGoing && !cancellationToken.IsCancellationRequested && !(sw.Elapsed > duration) && i < maxIterations)
            {
                //Apply to whole group if mode is all
                if (mode == IteratorEffectMode.All)
                {
                    effectFunction(group, cancellationToken, waitTime());

                    await Task.Delay(waitTime(), cancellationToken).ConfigureAwait(false);

                    i++;
                    continue;
                }

                if (reverse)
                {
                    lights.Reverse();
                }
                if (mode == IteratorEffectMode.Random || mode == IteratorEffectMode.RandomOrdered)
                {
                    lights = lights.OrderBy(x => Guid.NewGuid()).ToList();
                }

                foreach (var light in lights.Skip(reverse ? 1 : 0))
                {
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        effectFunction(new List <EntertainmentLight>()
                        {
                            light
                        }, cancellationToken, waitTime());

                        if (mode != IteratorEffectMode.AllIndividual)
                        {
                            await Task.Delay(waitTime(), cancellationToken).ConfigureAwait(false);
                        }
                    }
                }

                if (mode == IteratorEffectMode.AllIndividual)
                {
                    await Task.Delay(waitTime(), cancellationToken).ConfigureAwait(false);
                }

                keepGoing = mode == IteratorEffectMode.Single ? false : true;
                if (mode == IteratorEffectMode.Bounce)
                {
                    reverse = true;
                }

                i++;
            }
        }
Exemple #12
0
        /// <summary>
        /// Apply the groupFunction repeatedly to a list of groups of lights
        /// </summary>
        /// <param name="list"></param>
        /// <param name="groupFunction"></param>
        /// <param name="mode"></param>
        /// <param name="waitTime"></param>
        /// <param name="duration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task IteratorEffect(this IEnumerable <IEnumerable <EntertainmentLight> > list, CancellationToken cancellationToken, IteratorEffectFunc groupFunction, IteratorEffectMode mode, IteratorEffectMode secondaryMode, Func <TimeSpan> waitTime, TimeSpan?duration = null, int maxIterations = int.MaxValue)
        {
            if (waitTime == null)
            {
                waitTime = () => TimeSpan.FromSeconds(1);
            }
            if (duration == null)
            {
                duration = TimeSpan.MaxValue;
            }

            int secondaryMaxIterations = 1;

            //Normalize secondary iterator mode
            switch (secondaryMode)
            {
            case IteratorEffectMode.Bounce:
                secondaryMaxIterations = 2;
                break;

            case IteratorEffectMode.Cycle:
            case IteratorEffectMode.Single:
                secondaryMode = IteratorEffectMode.Single;
                break;

            case IteratorEffectMode.Random:
            case IteratorEffectMode.RandomOrdered:
                secondaryMode = IteratorEffectMode.RandomOrdered;
                break;

            case IteratorEffectMode.All:
            case IteratorEffectMode.AllIndividual:
            default:
                break;
            }

            bool keepGoing = true;
            var  groups    = list.ToList();
            bool reverse   = false;

            if (mode == IteratorEffectMode.RandomOrdered)
            {
                groups = groups.OrderBy(x => Guid.NewGuid()).ToList();
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();

            int i = 0;

            while (keepGoing && !cancellationToken.IsCancellationRequested && !(sw.Elapsed > duration) && i < maxIterations)
            {
                //Apply to all groups if mode is all
                if (mode == IteratorEffectMode.All)
                {
                    var flatGroup = list.SelectMany(x => x);
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        groupFunction(flatGroup, cancellationToken, waitTime());
                    }

                    //foreach (var group in list)
                    //{
                    //  if (!cancellationToken.IsCancellationRequested)
                    //    await groupFunction(group, waitTime);
                    //}

                    await Task.Delay(waitTime(), cancellationToken).ConfigureAwait(false);

                    i++;
                    continue;
                }

                if (reverse)
                {
                    groups.Reverse();
                }
                if (mode == IteratorEffectMode.Random)
                {
                    groups = groups.OrderBy(x => Guid.NewGuid()).ToList();
                }

                if (mode == IteratorEffectMode.AllIndividual)
                {
                    List <Task> allIndividualTasks = new List <Task>();
                    foreach (var group in groups.Skip(reverse ? 1 : 0).Where(x => x.Any()))
                    {
                        //Do not await, AllIndividual runs them all at the same time
                        var t = group.IteratorEffect(cancellationToken, groupFunction, secondaryMode, waitTime, maxIterations: secondaryMaxIterations);
                        allIndividualTasks.Add(t);
                    }

                    await Task.WhenAll(allIndividualTasks).ConfigureAwait(false);
                }
                else
                {
                    foreach (var group in groups.Skip(reverse ? 1 : 0).Where(x => x.Any()))
                    {
                        await group.IteratorEffect(cancellationToken, groupFunction, secondaryMode, waitTime, maxIterations : secondaryMaxIterations).ConfigureAwait(false);
                    }
                }

                keepGoing = mode == IteratorEffectMode.Single || mode == IteratorEffectMode.RandomOrdered ? false : true;
                if (mode == IteratorEffectMode.Bounce)
                {
                    reverse = true;
                }

                i++;
            }
        }
        /// <summary>
        /// Apply the effectFunction repeatedly to a group of lights
        /// </summary>
        /// <param name="group"></param>
        /// <param name="effectFunction"></param>
        /// <param name="mode"></param>
        /// <param name="waitTime"></param>
        /// <param name="duration"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task IteratorEffect(this IEnumerable <StreamingLight> group, IteratorEffectFunc effectFunction, IteratorEffectMode mode, Ref <TimeSpan?> waitTime, TimeSpan?duration = null, CancellationToken cancellationToken = new CancellationToken())
        {
            if (waitTime == null)
            {
                waitTime = TimeSpan.FromSeconds(1);
            }
            if (duration == null)
            {
                duration = TimeSpan.MaxValue;
            }

            bool keepGoing = true;
            var  lights    = group.ToList();
            bool reverse   = false;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            while (keepGoing && !cancellationToken.IsCancellationRequested && !(sw.Elapsed > duration))
            {
                //Apply to whole group if mode is all
                if (mode == IteratorEffectMode.All)
                {
                    await effectFunction(group, waitTime);

                    await Task.Delay(waitTime.Value.Value);

                    continue;
                }

                if (reverse)
                {
                    lights.Reverse();
                }
                if (mode == IteratorEffectMode.Random)
                {
                    lights = lights.OrderBy(x => Guid.NewGuid()).ToList();
                }

                foreach (var light in lights.Skip(reverse ? 1 : 0))
                {
                    await effectFunction(new List <StreamingLight>() { light }, waitTime);

                    if (mode != IteratorEffectMode.AllIndividual)
                    {
                        await Task.Delay(waitTime.Value.Value);
                    }
                }

                if (mode == IteratorEffectMode.AllIndividual)
                {
                    await Task.Delay(waitTime.Value.Value);
                }

                keepGoing = mode == IteratorEffectMode.Single ? false : true;
                if (mode == IteratorEffectMode.Bounce)
                {
                    reverse = true;
                }
            }
        }
Exemple #14
0
        public Task Start(IEnumerable <IEnumerable <EntertainmentLight> > layer, Func <TimeSpan> waitTime, RGBColor?color, IteratorEffectMode iteratorMode, IteratorEffectMode secondaryIteratorMode, CancellationToken cancellationToken)
        {
            if (!color.HasValue)
            {
                color = RGBColor.Random();
            }

            if (iteratorMode != IteratorEffectMode.All)
            {
                if (secondaryIteratorMode == IteratorEffectMode.Bounce ||
                    secondaryIteratorMode == IteratorEffectMode.Cycle ||
                    secondaryIteratorMode == IteratorEffectMode.Random ||
                    secondaryIteratorMode == IteratorEffectMode.RandomOrdered ||
                    secondaryIteratorMode == IteratorEffectMode.Single)
                {
                    Func <TimeSpan> customWaitMS = () => TimeSpan.FromMilliseconds((waitTime().TotalMilliseconds *layer.Count()) / layer.SelectMany(x => x).Count());

                    return(layer.FlashQuick(cancellationToken, color, iteratorMode, secondaryIteratorMode, waitTime: customWaitMS));
                }
            }

            return(layer.FlashQuick(cancellationToken, color, iteratorMode, secondaryIteratorMode, waitTime: waitTime));
        }
Exemple #15
0
        public Task Start(IEnumerable <IEnumerable <EntertainmentLight> > layer, Func <TimeSpan> waitTime, RGBColor?color, IteratorEffectMode iteratorMode, IteratorEffectMode secondaryIteratorMode, CancellationToken cancellationToken)
        {
            if (!color.HasValue)
            {
                color = RGBColor.Random();
            }

            if (iteratorMode == IteratorEffectMode.All)
            {
                iteratorMode = IteratorEffectMode.AllIndividual;
            }

            //This is no fun, no action, change it to cycle
            if (iteratorMode == IteratorEffectMode.AllIndividual &&
                (secondaryIteratorMode == IteratorEffectMode.All || secondaryIteratorMode == IteratorEffectMode.AllIndividual))
            {
                secondaryIteratorMode = IteratorEffectMode.Cycle;
            }

            if (iteratorMode != IteratorEffectMode.AllIndividual)
            {
                if (secondaryIteratorMode == IteratorEffectMode.Bounce ||
                    secondaryIteratorMode == IteratorEffectMode.Cycle ||
                    secondaryIteratorMode == IteratorEffectMode.Random ||
                    secondaryIteratorMode == IteratorEffectMode.RandomOrdered ||
                    secondaryIteratorMode == IteratorEffectMode.Single)
                {
                    Func <TimeSpan> customWaitMS  = () => TimeSpan.FromMilliseconds((waitTime().TotalMilliseconds *layer.Count()) / layer.SelectMany(x => x).Count());
                    Func <TimeSpan> customOnTime  = () => customWaitMS() / 2;
                    Func <TimeSpan> customOffTime = () => customWaitMS() * 2;

                    return(layer.Flash(cancellationToken, color, iteratorMode, secondaryIteratorMode, waitTime: customWaitMS, transitionTimeOn: customOnTime, transitionTimeOff: customOffTime, waitTillFinished: false));
                }
            }

            Func <TimeSpan> onTime  = () => waitTime() / 2;
            Func <TimeSpan> offTime = () => waitTime() * 2;

            return(layer.Flash(cancellationToken, color, iteratorMode, secondaryIteratorMode, waitTime: waitTime, transitionTimeOn: onTime, transitionTimeOff: offTime, waitTillFinished: false));
        }