>
        /// <param name="g">Green exponent 0-255</param>
        /// <param name="b">Blue exponent 0-255</param>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        public void SetKeyColor(TesoroLedId key, int r, int g, int b, TesoroProfile profile)
        {
            if (_device is null) throw new InvalidOperationException(UninitializedMessage);

            if (key == TesoroLedId.None) return;

            // Prepare the command data
            byte[] data = { 0x07, 0x0D, (byte)profile, (byte)key, IntToByte(r), IntToByte(g), IntToByte(b), 0x00 };

            // Send the data
            _device.writeFeature(data);
        }

        /// <summary>
        /// Sets the LED of a single key using 0-255 integers.
        /// </summary>
        /// <param name="key">Key</param>
        /// <param name="r">Red exponent 0-255</param>
        /// <param name="g">Green exponent 0-255</param>
        /// <param name="b">Blue exponent 0-255</param>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        /// <param name="waitTime">Wait for completion.</param>
        /// <param name="cancellationToken">Cancellation token</param>
        public async Task SetKeyColorAsync(TesoroLedId key, int r, int g, int b, TesoroProfile profile, TimeSpan? waitTime = null, CancellationToken cancellationToken = default)
        {
            SetKeyColor(key, r, g, b, profile);

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

        /// <summary>
        /// Sets the LED of a single key using 0-255 integers.
        /// </summary>
        /// <param name="key">Key in integer. Should be between 0 and 255 inclusive</param>
        /// <param name="r">Red exponent 0-255</param>
        /// <param name="g">Green exponent 0-255</param>
        /// <param name="b">Blue exponent 0-255</param>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        /// <param name="waitTime">Wait for completion.</param>
        /// <param name="cancellationToken">Cancellation token</param>
        public async Task SetKeyColorAsync(int key, int r, int g, int b, TesoroProfile profile, TimeSpan? waitTime = null, CancellationToken cancellationToken = default)
        {
            SetKeyColor((TesoroLedId)Convert.ToByte(key), r, g, b, profile);

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

        /// <summary>
        /// Set all LEDs using a Bitmap object. Image will be scaled to fit the keyboard
        /// </summary>
        /// <param name="bitmap">A Bitmap object describing the desired pattern.</param>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        /// <param name="fast">True - speeds up execution at the risk of missed pixels. Recommended true for animated effects, false for static effects.</param>
        private void SetKeysColor(Bitmap bitmap, TesoroProfile profile, bool fast)
        {
            if (bitmap.Width > Width || bitmap.Height > Height) bitmap = new Bitmap(bitmap, Width, Height);
            for (var x = 0; x < Width; x++)
            {
                for (var y = 0; y < Height; y++)
                {
                    // get pixel (using tiling for small bitmaps)
                    var col = bitmap.GetPixel(x, y);

                    // set Color
                    SetKeyColor(_keyPositions[x, y], col.R, col.G, col.B, profile);
                    // delay between sends
                    Wait(fast);
                }
            }
        }

        /// <summary>
        /// Set the LEDs for all using an image file. Image will be scaled to fit the keyboard
        /// </summary>
        /// <param name="file">Path to an image file describing the desired pattern.</param>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        /// <param name="fast">True - speeds up execution at the risk of missed pixels. Recommended true for animated effects, false for static effects.</param>
        public void SetKeysColor(string file, TesoroProfile profile, bool fast)
        {
            var image = Image.FromFile(file);

            SetKeysColor(new Bitmap(image), profile, fast);
        }

        /// <summary>
        /// Turn off all LEDs.
        /// </summary>
        /// <param name="profile">The profile to modify. This should be the active profile.</param>
        public void ClearSpectrumColors(TesoroProfile profile)
        {
            if (_device is null) throw new InvalidOperationException(UninitializedMessage);

            // Prepare the command data
            byte[] data = { 0x07, 0x0D, (byte)profile, 0xFE, 0x00, 0x00, 0x00, 0x00 };

            // Send the data
            _device.writeFeature(data);
        }

        /// <summary>
        /// Save the current Spectrum Color layout to the keyboard.
        /// Changing profile without saving first will lose all changes made to the profile.
        /// </summary>
        /// <param name="profile">The profile to save. This should be the active profile.</param>
        public void SaveSpectrumColors(TesoroProfile profile)
        {
            if (_device is null) throw new InvalidOperationException(UninitializedMessage);

            // Prepare the command data
            byte[] data = { 0x07, 0x0D, (byte)profile, 0xFF, 0x00, 0x00, 0x00, 0x00 };

            // Send the data
            _device.writeFeature(data);
        }

        public async Task SaveSpectrumColorsAsync(TesoroProfile profile, TimeSpan? waitTime = null, CancellationToken cancellationToken = default)
        {
            SaveSpectrumColors(profile);

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

        /// <summary>
        /// Perform a short wait. For use in between successive calls.
        /// </summary>
        /// <param name="fast">True - Shorter delay for use in animation effect. When keys are set with fast delay, some leds may not be set. False - Longer delay for safely assigning</param>
        private static void Wait(bool fast)
        {
            if (fast)
            {
                var watch = new Stopwatch();
                watch.Start();
                while (watch.Elapsed.TotalMilliseconds < 0.8)
                {
                    // waiting for.8ms
                }
            }
            else
            {
                Thread.Sleep(1);
            }
        }

        /// <summary>
        /// Initializes the key positions array.
        /// </summary>
        private void SetKeyPositions()
        {
            for (var x = 0; x < Width; x++)
            {
                for (var y = 0; y < Height; y++)
                {
                    SetKeyPosition(TesoroLedId.None, x, y);
                }
            }

            // Row 1
            SetKeyPosition(TesoroLedId.Escape, 0, 0);
            SetKeyPosition(TesoroLedId.F1, 2, 0);
            SetKeyPosition(TesoroLedId.F2, 3, 0);
            SetKeyPosition(TesoroLedId.F3, 4, 0);
            SetKeyPosition(TesoroLedId.F4, 5, 0);
            SetKeyPosition(TesoroLedId.F5, 6, 0);
            SetKeyPosition(TesoroLedId.F6, 7, 0);
            SetKeyPosition(TesoroLedId.F7, 8, 0);
            SetKeyPosition(TesoroLedId.F8, 9, 0);
            SetKeyPosition(TesoroLedId.F9, 11, 0);
            SetKeyPosition(TesoroLedId.F10, 12, 0);
            SetKeyPosition(TesoroLedId.F11, 13, 0