diff --git a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
index ff2f7df6..717ac8ac 100644
--- a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
+++ b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
+using System.Runtime.CompilerServices;
 
 namespace RGB.NET.Core;
 
@@ -94,6 +95,15 @@ public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwE
             Reset();
             throw;
         }
+        catch (RGBDeviceException)
+        {
+            Reset();
+            if (throwExceptions)
+            {
+                throw;
+            }
+            return false;
+        }
         catch (Exception ex)
         {
             Reset();
@@ -158,6 +168,7 @@ protected virtual IEnumerable<IRGBDevice> GetLoadedDevices(RGBDeviceType loadFil
     /// <param name="id">The id of the update trigger.</param>
     /// <param name="updateRateHardLimit">The update rate hard limit to be set in the update trigger.</param>
     /// <returns>The update trigger mapped to the specified id.</returns>
+    [MethodImpl(MethodImplOptions.Synchronized)]
     protected virtual IDeviceUpdateTrigger GetUpdateTrigger(int id = -1, double? updateRateHardLimit = null)
     {
         if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
diff --git a/RGB.NET.Core/Ids/IdGenerator.cs b/RGB.NET.Core/Ids/IdGenerator.cs
index f9bf2177..435cfcff 100644
--- a/RGB.NET.Core/Ids/IdGenerator.cs
+++ b/RGB.NET.Core/Ids/IdGenerator.cs
@@ -13,8 +13,8 @@ public static class IdGenerator
 
     // ReSharper disable InconsistentNaming
     private static readonly HashSet<string> _registeredIds = [];
-    private static readonly Dictionary<Assembly, Dictionary<string, string>> _idMappings = [];
-    private static readonly Dictionary<Assembly, Dictionary<string, int>> _counter = [];
+    private static readonly Dictionary<object, Dictionary<string, string>> _idMappings = [];
+    private static readonly Dictionary<object, Dictionary<string, int>> _counter = [];
     // ReSharper restore InconsistentNaming
 
     #endregion
@@ -29,7 +29,7 @@ public static class IdGenerator
     [MethodImpl(MethodImplOptions.NoInlining)]
     public static string MakeUnique(string id) => MakeUnique(Assembly.GetCallingAssembly(), id);
 
-    internal static string MakeUnique(Assembly callingAssembly, string id)
+    public static string MakeUnique(object callingAssembly, string id)
     {
         if (!_idMappings.TryGetValue(callingAssembly, out Dictionary<string, string>? idMapping))
         {
@@ -63,7 +63,7 @@ internal static string MakeUnique(Assembly callingAssembly, string id)
     [MethodImpl(MethodImplOptions.NoInlining)]
     public static void ResetCounter() => ResetCounter(Assembly.GetCallingAssembly());
 
-    internal static void ResetCounter(Assembly callingAssembly)
+    public static void ResetCounter(object callingAssembly)
     {
         if (_counter.TryGetValue(callingAssembly, out Dictionary<string, int>? counter))
             counter.Clear();
diff --git a/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs b/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
index a45ae6ca..2957fb85 100644
--- a/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
+++ b/RGB.NET.Core/Update/Devices/DeviceUpdateTrigger.cs
@@ -141,11 +141,15 @@ public virtual async void Stop()
 
         UpdateTokenSource?.Cancel();
         if (UpdateTask != null)
-            try { await UpdateTask.ConfigureAwait(false); }
+            try
+            {
+                await UpdateTask.ConfigureAwait(false);
+                UpdateTask?.Dispose();
+            }
             catch (TaskCanceledException) { }
             catch (OperationCanceledException) { }
+            catch (InvalidOperationException) { }
 
-        UpdateTask?.Dispose();
         UpdateTask = null;
     }
 
diff --git a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
index 4dba9ea8..e4d13adf 100644
--- a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
+++ b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
@@ -3,6 +3,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Threading;
 using RGB.NET.Core;
 using RGB.NET.Devices.Corsair.Native;
@@ -103,6 +104,7 @@ public CorsairDeviceProvider()
 
     protected override void InitializeSDK()
     {
+        _CUESDK.SessionStateChanged -= CancelOnConnect;
         _CUESDK.Reload();
 
         using ManualResetEventSlim waitEvent = new(false);
@@ -124,13 +126,17 @@ void OnInitializeSessionStateChanged(object? sender, CorsairSessionState state)
                 Throw(new RGBDeviceException($"Failed to initialized Corsair-SDK. (ErrorCode: {errorCode})"));
 
             if (!waitEvent.Wait(ConnectionTimeout))
-                Throw(new RGBDeviceException($"Failed to initialized Corsair-SDK. (Timeout - Current connection state: {_CUESDK.SesionState})"));
+            {
+                _CUESDK.SessionStateChanged += CancelOnConnect; //We can't cancel connection. All we can do is disconnect after connection
+                Throw(new RGBDeviceException($"Failed to initialized Corsair-SDK. (Timeout - Current connection state: {_CUESDK.SessionState})"));
+            }
 
             _CUESDK.CorsairGetSessionDetails(out _CorsairSessionDetails? details);
             if (errorCode != CorsairError.Success)
                 Throw(new RGBDeviceException($"Failed to get session details. (ErrorCode: {errorCode})"));
 
             SessionDetails = new CorsairSessionDetails(details!);
+            _CUESDK.DeviceConnectionEvent += OnDeviceConnectionEvent;
         }
         finally
         {
@@ -138,6 +144,39 @@ void OnInitializeSessionStateChanged(object? sender, CorsairSessionState state)
         }
     }
 
+    private void CancelOnConnect(object? sender, CorsairSessionState e)
+    {
+        if (e != CorsairSessionState.Connected) return;
+        _CUESDK.SessionStateChanged -= CancelOnConnect;
+        _CUESDK.CorsairDisconnect();
+    }
+
+    private void OnDeviceConnectionEvent(object? sender, _CorsairDeviceConnectionStatusChangedEvent connectionStatusChangedEvent)
+    {
+        string? deviceId = connectionStatusChangedEvent.deviceId;
+        if (string.IsNullOrWhiteSpace(deviceId)) return;
+        if (connectionStatusChangedEvent.isConnected)
+        {
+            _CUESDK.CorsairGetDeviceInfo(deviceId, out _CorsairDeviceInfo deviceInfo);
+            IDeviceUpdateTrigger deviceUpdateTrigger = GetUpdateTrigger();
+            IEnumerable<ICorsairRGBDevice> device = LoadDevice(deviceInfo, deviceUpdateTrigger);
+            foreach (ICorsairRGBDevice corsairRGBDevice in device)
+            {
+                corsairRGBDevice.Initialize();
+                if (AddDevice(corsairRGBDevice))
+                {
+                    deviceUpdateTrigger.Start();
+                }
+            }
+        }
+        else
+        {
+            IRGBDevice? removedDevice = Devices.FirstOrDefault(device => ((ICorsairRGBDevice)device).DeviceId == deviceId);
+            if (removedDevice == null) return;
+            RemoveDevice(removedDevice);    //TODO disposing the device disposes device queue!
+        }
+    }
+
     private void OnSessionStateChanged(object? sender, CorsairSessionState state) => SessionState = state;
 
     /// <inheritdoc />
@@ -156,170 +195,171 @@ private IEnumerable<ICorsairRGBDevice> LoadCorsairDevices()
         if (error != CorsairError.Success)
             Throw(new RGBDeviceException($"Failed to load devices. (ErrorCode: {error})"));
 
-        foreach (_CorsairDeviceInfo device in devices)
+        return devices.SelectMany(LoadDevice);
+    }
+
+    private IEnumerable<ICorsairRGBDevice> LoadDevice(_CorsairDeviceInfo device)
+    {
+        return LoadDevice(device, GetUpdateTrigger());
+    }
+
+    private IEnumerable<ICorsairRGBDevice> LoadDevice(_CorsairDeviceInfo device, IDeviceUpdateTrigger updateTrigger)
+    {
+        if (string.IsNullOrWhiteSpace(device.id)) yield break;
+
+        // sometimes it is okay to fail :) (can cause problems with reconnections)
+        _CUESDK.CorsairRequestControl(device.id, ExclusiveAccess ? CorsairAccessLevel.ExclusiveLightingControl : CorsairAccessLevel.Shared);
+
+        CorsairDeviceUpdateQueue updateQueue = new(updateTrigger, device);
+
+        int channelLedCount = 0;
+        for (int i = 0; i < device.channelCount; i++)
         {
-            if (string.IsNullOrWhiteSpace(device.id)) continue;
+            Console.WriteLine($"Channel {i}/{device.channelCount}");
+            channelLedCount += _CUESDK.ReadDevicePropertySimpleInt32(device.id!, CorsairDevicePropertyId.ChannelLedCount, (uint)i);
+        }
 
-            error = _CUESDK.CorsairRequestControl(device.id, ExclusiveAccess ? CorsairAccessLevel.ExclusiveLightingControl : CorsairAccessLevel.Shared);
-            if (error != CorsairError.Success)
-                Throw(new RGBDeviceException($"Failed to take control of device '{device.id}'. (ErrorCode: {error})"));
+        int deviceLedCount = device.ledCount - channelLedCount;
+        if (deviceLedCount > 0)
+        {
+            ICorsairRGBDevice singleChannelDevice = CreateSingleChannelDevice(device, deviceLedCount, updateQueue);
+            yield return singleChannelDevice;
+        }
 
-            CorsairDeviceUpdateQueue updateQueue = new(GetUpdateTrigger(), device);
 
-            int channelLedCount = 0;
-            for (int i = 0; i < device.channelCount; i++)
-            {
-                Console.WriteLine($"Channel {i}/{device.channelCount}");
-                channelLedCount += _CUESDK.ReadDevicePropertySimpleInt32(device.id!, CorsairDevicePropertyId.ChannelLedCount, (uint)i);
-            }
+        int offset = deviceLedCount;
+        for (int i = 0; i < device.channelCount; i++)
+        {
+            int deviceCount = _CUESDK.ReadDevicePropertySimpleInt32(device.id!, CorsairDevicePropertyId.ChannelDeviceCount, (uint)i);
+            if (deviceCount <= 0)
+                continue; // DarthAffe 10.02.2023: There seem to be an issue in the SDK where it reports empty channels and fails
+                          // when getting ledCounts and device types from them
 
-            int deviceLedCount = device.ledCount - channelLedCount;
-            if (deviceLedCount > 0)
-                switch (device.type)
-                {
-                    case CorsairDeviceType.Keyboard:
-                        yield return new CorsairKeyboardRGBDevice(new CorsairKeyboardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Mouse:
-                        yield return new CorsairMouseRGBDevice(new CorsairMouseRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Headset:
-                        yield return new CorsairHeadsetRGBDevice(new CorsairHeadsetRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Mousemat:
-                        yield return new CorsairMousepadRGBDevice(new CorsairMousepadRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.HeadsetStand:
-                        yield return new CorsairHeadsetStandRGBDevice(new CorsairHeadsetStandRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.MemoryModule:
-                        yield return new CorsairMemoryRGBDevice(new CorsairMemoryRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Motherboard:
-                        yield return new CorsairMainboardRGBDevice(new CorsairMainboardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.GraphicsCard:
-                        yield return new CorsairGraphicsCardRGBDevice(new CorsairGraphicsCardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Touchbar:
-                        yield return new CorsairTouchbarRGBDevice(new CorsairTouchbarRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.Cooler:
-                        yield return new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.GameController:
-                        yield return new CorsairGameControllerRGBDevice(new CorsairGameControllerRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    case CorsairDeviceType.FanLedController:
-                    case CorsairDeviceType.LedController:
-                    case CorsairDeviceType.Unknown:
-                        yield return new CorsairUnknownRGBDevice(new CorsairUnknownRGBDeviceInfo(device, deviceLedCount, 0), updateQueue);
-                        break;
-
-                    default:
-                        Throw(new RGBDeviceException("Unknown Device-Type"));
-                        break;
-                }
+            int[] ledCounts =
+                _CUESDK.ReadDevicePropertySimpleInt32Array(device.id!, CorsairDevicePropertyId.ChannelDeviceLedCountArray, (uint)i);
+            int[] deviceTypes = _CUESDK.ReadDevicePropertySimpleInt32Array(device.id!, CorsairDevicePropertyId.ChannelDeviceTypeArray, (uint)i);
 
-            int offset = deviceLedCount;
-            for (int i = 0; i < device.channelCount; i++)
+            for (int j = 0; j < deviceCount; j++)
             {
-                int deviceCount = _CUESDK.ReadDevicePropertySimpleInt32(device.id!, CorsairDevicePropertyId.ChannelDeviceCount, (uint)i);
-                if (deviceCount <= 0) continue; // DarthAffe 10.02.2023: There seem to be an issue in the SDK where it reports empty channels and fails when getting ledCounts and device types from them
+                CorsairChannelDeviceType deviceType = (CorsairChannelDeviceType)deviceTypes[j];
+                int ledCount = ledCounts[j];
 
-                int[] ledCounts = _CUESDK.ReadDevicePropertySimpleInt32Array(device.id!, CorsairDevicePropertyId.ChannelDeviceLedCountArray, (uint)i);
-                int[] deviceTypes = _CUESDK.ReadDevicePropertySimpleInt32Array(device.id!, CorsairDevicePropertyId.ChannelDeviceTypeArray, (uint)i);
+                yield return CreateCorsairDeviceChannel(device, deviceType, ledCount, offset, updateQueue);
 
-                for (int j = 0; j < deviceCount; j++)
-                {
-                    CorsairChannelDeviceType deviceType = (CorsairChannelDeviceType)deviceTypes[j];
-                    int ledCount = ledCounts[j];
-
-                    switch (deviceType)
-                    {
-                        case CorsairChannelDeviceType.FanHD:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "HD Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.FanSP:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "SP Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.FanLL:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "LL Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.FanML:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "ML Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.FanQL:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "QL Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.FanQX:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "QX Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.EightLedSeriesFan:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "8-Led-Series Fan Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.DAP:
-                            yield return new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "DAP Fan"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.Pump:
-                            yield return new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, ledCount, offset, "Pump"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.WaterBlock:
-                            yield return new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, ledCount, offset, "Water Block"), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.Strip:
-                            string modelName = "LED Strip";
-
-                            // LS100 Led Strips are reported as one big strip if configured in monitor mode in iCUE, 138 LEDs for dual monitor, 84 for single
-                            if ((device.model == "LS100 Starter Kit") && (ledCount == 138))
-                                modelName = "LS100 LED Strip (dual monitor)";
-                            else if ((device.model == "LS100 Starter Kit") && (ledCount == 84))
-                                modelName = "LS100 LED Strip (single monitor)";
-                            // Any other value means an "External LED Strip" in iCUE, these are reported per-strip, 15 for short strips, 27 for long
-                            else if ((device.model == "LS100 Starter Kit") && (ledCount == 15))
-                                modelName = "LS100 LED Strip (short)";
-                            else if ((device.model == "LS100 Starter Kit") && (ledCount == 27))
-                                modelName = "LS100 LED Strip (long)";
-
-                            yield return new CorsairLedStripRGBDevice(new CorsairLedStripRGBDeviceInfo(device, ledCount, offset, modelName), updateQueue);
-                            break;
-
-                        case CorsairChannelDeviceType.DRAM:
-                            yield return new CorsairMemoryRGBDevice(new CorsairMemoryRGBDeviceInfo(device, ledCount, offset, "DRAM"), updateQueue);
-                            break;
-
-                        default:
-                            Throw(new RGBDeviceException("Unknown Device-Type"));
-                            break;
-                    }
-
-                    offset += ledCount;
-                }
+                offset += ledCount;
             }
         }
     }
 
+    private static ICorsairRGBDevice CreateSingleChannelDevice(_CorsairDeviceInfo device, int deviceLedCount, CorsairDeviceUpdateQueue updateQueue)
+    {
+        return device.type switch
+        {
+            CorsairDeviceType.Keyboard =>
+                new CorsairKeyboardRGBDevice(new CorsairKeyboardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Mouse =>
+                new CorsairMouseRGBDevice(new CorsairMouseRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Headset =>
+                new CorsairHeadsetRGBDevice(new CorsairHeadsetRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Mousemat =>
+                new CorsairMousepadRGBDevice(new CorsairMousepadRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.HeadsetStand =>
+                new CorsairHeadsetStandRGBDevice(new CorsairHeadsetStandRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.MemoryModule =>
+                new CorsairMemoryRGBDevice(new CorsairMemoryRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Motherboard =>
+                new CorsairMainboardRGBDevice(new CorsairMainboardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.GraphicsCard =>
+                new CorsairGraphicsCardRGBDevice(new CorsairGraphicsCardRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Touchbar =>
+                new CorsairTouchbarRGBDevice(new CorsairTouchbarRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.Cooler =>
+                new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.GameController =>
+                new CorsairGameControllerRGBDevice(new CorsairGameControllerRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            CorsairDeviceType.FanLedController or 
+                CorsairDeviceType.LedController or 
+                CorsairDeviceType.Unknown =>
+                new CorsairUnknownRGBDevice(new CorsairUnknownRGBDeviceInfo(device, deviceLedCount, 0), updateQueue),
+
+            _ => throw new RGBDeviceException("Unknown Device-Type")
+        };
+    }
+
+    private static ICorsairRGBDevice CreateCorsairDeviceChannel(_CorsairDeviceInfo device, CorsairChannelDeviceType deviceType,
+                                                                int ledCount, int offset, CorsairDeviceUpdateQueue updateQueue)
+    {
+        return deviceType switch
+        {
+            CorsairChannelDeviceType.FanHD =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "HD Fan"), updateQueue),
+
+            CorsairChannelDeviceType.FanSP =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "SP Fan"), updateQueue),
+
+            CorsairChannelDeviceType.FanLL =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "LL Fan"), updateQueue),
+
+            CorsairChannelDeviceType.FanML =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "ML Fan"), updateQueue),
+
+            CorsairChannelDeviceType.FanQL =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "QL Fan"), updateQueue),
+
+            CorsairChannelDeviceType.FanQX =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "QX Fan"), updateQueue),
+
+            CorsairChannelDeviceType.EightLedSeriesFan =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "8-Led-Series Fan Fan"), updateQueue),
+
+            CorsairChannelDeviceType.DAP =>
+                new CorsairFanRGBDevice(new CorsairFanRGBDeviceInfo(device, ledCount, offset, "DAP Fan"), updateQueue),
+
+            CorsairChannelDeviceType.Pump =>
+                new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, ledCount, offset, "Pump"), updateQueue),
+
+            CorsairChannelDeviceType.WaterBlock =>
+                new CorsairCoolerRGBDevice(new CorsairCoolerRGBDeviceInfo(device, ledCount, offset, "Water Block"), updateQueue),
+
+            CorsairChannelDeviceType.Strip => CreateLedStripDevice(device, ledCount, offset, updateQueue),
+
+            CorsairChannelDeviceType.DRAM =>
+                new CorsairMemoryRGBDevice(new CorsairMemoryRGBDeviceInfo(device, ledCount, offset, "DRAM"), updateQueue),
+
+            _ => throw new RGBDeviceException("Unknown Device-Type")
+        };
+    }
+
+    private static CorsairLedStripRGBDevice CreateLedStripDevice(_CorsairDeviceInfo device, int ledCount, int offset, CorsairDeviceUpdateQueue updateQueue)
+    {
+        string modelName = "LED Strip";
+
+        // LS100 Led Strips are reported as one big strip if configured in monitor mode in iCUE, 138 LEDs for dual monitor, 84 for single
+        if ((device.model == "LS100 Starter Kit") && (ledCount == 138))
+            modelName = "LS100 LED Strip (dual monitor)";
+        else if ((device.model == "LS100 Starter Kit") && (ledCount == 84))
+            modelName = "LS100 LED Strip (single monitor)";
+        // Any other value means an "External LED Strip" in iCUE, these are reported per-strip, 15 for short strips, 27 for long
+        else if ((device.model == "LS100 Starter Kit") && (ledCount == 15))
+            modelName = "LS100 LED Strip (short)";
+        else if ((device.model == "LS100 Starter Kit") && (ledCount == 27))
+            modelName = "LS100 LED Strip (long)";
+
+        CorsairLedStripRGBDevice ledStripDevice = new(new CorsairLedStripRGBDeviceInfo(device, ledCount, offset, modelName), updateQueue);
+        return ledStripDevice;
+    }
+
     /// <inheritdoc />
     protected override void Dispose(bool disposing)
     {
@@ -333,6 +373,8 @@ protected override void Dispose(bool disposing)
             try { _CUESDK.UnloadCUESDK(); }
             catch { /* at least we tried */ }
 
+            IdGenerator.ResetCounter(typeof(CorsairDeviceProvider));
+
             _instance = null;
         }
     }
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairEventId.cs b/RGB.NET.Devices.Corsair/Enum/CorsairEventId.cs
new file mode 100644
index 00000000..c1b8988b
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairEventId.cs
@@ -0,0 +1,8 @@
+namespace RGB.NET.Devices.Corsair;
+
+internal enum CorsairEventId
+{
+    Invalid = 0,
+    DeviceConnectionStatusChangedEvent = 1,
+    KeyEvent = 2,
+}
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs
index 9fcbca62..3faa86ff 100644
--- a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs
@@ -14,6 +14,11 @@ public abstract class CorsairRGBDevice<TDeviceInfo> : AbstractRGBDevice<TDeviceI
 {
     #region Properties & Fields
 
+    /// <summary>
+    /// <inheritdoc cref="ICorsairRGBDevice"/>
+    /// </summary>
+    public string DeviceId => DeviceInfo.DeviceId;
+
     /// <summary>
     /// Gets the mapping of <see cref="LedId"/> to <see cref="CorsairLedId"/> used to update the LEDs of this device.
     /// </summary>
@@ -29,7 +34,7 @@ public abstract class CorsairRGBDevice<TDeviceInfo> : AbstractRGBDevice<TDeviceI
     /// <param name="info">The generic information provided by CUE for the device.</param>
     /// <param name="mapping">The mapping <see cref="LedId"/> to <see cref="CorsairLedId"/> used to update the LEDs of this device.</param>
     /// <param name="updateQueue">The queue used to update this device.</param>
-    protected CorsairRGBDevice(TDeviceInfo info, CorsairDeviceUpdateQueue updateQueue)
+    protected CorsairRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue)
         : base(info, updateQueue)
     { }
 
@@ -37,6 +42,24 @@ protected CorsairRGBDevice(TDeviceInfo info, CorsairDeviceUpdateQueue updateQueu
 
     #region Methods
 
+    protected bool Equals(CorsairRGBDevice<TDeviceInfo> other)
+    {
+        return DeviceId == other.DeviceId;
+    }
+
+    public override bool Equals(object? obj)
+    {
+        if (ReferenceEquals(null, obj)) return false;
+        if (ReferenceEquals(this, obj)) return true;
+        if (obj.GetType() != this.GetType()) return false;
+        return Equals((CorsairRGBDevice<TDeviceInfo>)obj);
+    }
+
+    public override int GetHashCode()
+    {
+        return DeviceId.GetHashCode();
+    }
+
     void ICorsairRGBDevice.Initialize() => InitializeLayout();
 
     /// <summary>
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs
index 6137b95a..c7560bbb 100644
--- a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs
@@ -1,4 +1,7 @@
-using System.Text.RegularExpressions;
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
 using RGB.NET.Core;
 using RGB.NET.Devices.Corsair.Native;
 
@@ -33,7 +36,7 @@ public class CorsairRGBDeviceInfo : IRGBDeviceInfo
     /// Returns the unique ID provided by the Corsair-SDK.
     /// Returns string.Empty for Custom devices.
     /// </summary>
-    public string DeviceId { get; }
+    public string DeviceId { get; init; }
 
     /// <inheritdoc />
     public object? LayoutMetadata { get; set; }
@@ -67,7 +70,14 @@ internal CorsairRGBDeviceInfo(RGBDeviceType deviceType, _CorsairDeviceInfo nativ
         this.LedCount = ledCount;
         this.LedOffset = ledOffset;
 
-        DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);
+        if (nativeInfo.id == null)  // this device is 99% unpluggable
+        {
+            DeviceName = IdGenerator.MakeUnique(typeof(CorsairDeviceProvider), Manufacturer + " " + Model);
+        }
+        else
+        {
+            DeviceName = Manufacturer + " " + Model + " #" + HashAndShorten(DeviceId);
+        }
     }
 
     /// <summary>
@@ -86,7 +96,34 @@ internal CorsairRGBDeviceInfo(RGBDeviceType deviceType, _CorsairDeviceInfo nativ
         this.LedCount = ledCount;
         this.LedOffset = ledOffset;
 
-        DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);
+        if (nativeInfo.id == null)
+        {
+            DeviceName = IdGenerator.MakeUnique(typeof(CorsairDeviceProvider),Manufacturer + " " + Model) + " " + ledOffset;;
+        }
+        else
+        {
+            DeviceName = Manufacturer + " " + Model + " #" + HashAndShorten(DeviceId) + " " + ledOffset;
+        }
+    }
+
+    #endregion
+
+    #region Methods
+
+    private static string HashAndShorten(string input)
+    {
+        using SHA256 sha256Hash = SHA256.Create();
+        byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
+        // Take the first 4 bytes of the hash
+        byte[] shortenedBytes = new byte[4];
+        Array.Copy(bytes, shortenedBytes, 4);
+        // Convert the bytes to a string
+        StringBuilder shortenedHash = new();
+        foreach (byte b in shortenedBytes)
+        {
+            shortenedHash.Append(b.ToString("X2"));
+        }
+        return shortenedHash.ToString();
     }
 
     #endregion
diff --git a/RGB.NET.Devices.Corsair/Generic/ICorsairRGBDevice.cs b/RGB.NET.Devices.Corsair/Generic/ICorsairRGBDevice.cs
index 5e49da25..9bfde69a 100644
--- a/RGB.NET.Devices.Corsair/Generic/ICorsairRGBDevice.cs
+++ b/RGB.NET.Devices.Corsair/Generic/ICorsairRGBDevice.cs
@@ -7,5 +7,7 @@ namespace RGB.NET.Devices.Corsair;
 /// </summary>
 public interface ICorsairRGBDevice : IRGBDevice
 {
+    internal string DeviceId { get; }
+
     internal void Initialize();
 }
\ No newline at end of file
diff --git a/RGB.NET.Devices.Corsair/Native/_CUESDK.cs b/RGB.NET.Devices.Corsair/Native/_CUESDK.cs
index 00d9f922..70a8b4d4 100644
--- a/RGB.NET.Devices.Corsair/Native/_CUESDK.cs
+++ b/RGB.NET.Devices.Corsair/Native/_CUESDK.cs
@@ -12,6 +12,7 @@
 namespace RGB.NET.Devices.Corsair.Native;
 
 internal delegate void CorsairSessionStateChangedHandler(nint context, _CorsairSessionStateChanged eventData);
+internal delegate void CorsairEventHandler(nint context, _CorsairEvent corsairEvent);
 
 // ReSharper disable once InconsistentNaming
 internal static unsafe class _CUESDK
@@ -47,23 +48,59 @@ internal static unsafe class _CUESDK
 
     #region Properties & Fields
 
-    internal static bool IsConnected => SesionState == CorsairSessionState.Connected;
-    internal static CorsairSessionState SesionState { get; private set; }
+    internal static bool IsConnected => SessionState == CorsairSessionState.Connected;
+    internal static CorsairSessionState SessionState { get; private set; }
 
     #endregion
 
     #region Events
 
     internal static event EventHandler<CorsairSessionState>? SessionStateChanged;
+    internal static event EventHandler<_CorsairDeviceConnectionStatusChangedEvent>? DeviceConnectionEvent;
 
     #endregion
 
     #region Methods
 
-    private static void CorsairSessionStateChangedCallback(nint context, _CorsairSessionStateChanged eventdata)
+    private static void CorsairSessionStateChangedCallback(nint context, _CorsairSessionStateChanged eventData)
     {
-        SesionState = eventdata.state;
-        SessionStateChanged?.Invoke(null, eventdata.state);
+        SessionState = eventData.state;
+        try
+        {
+            SessionStateChanged?.Invoke(null, eventData.state);
+        }
+        catch { /* dont let exception go to sdk */ }
+
+        switch (eventData.state)
+        {
+            case CorsairSessionState.Connected:
+                _corsairSubscribeForEvents(CorsairEventCallback, 0);
+                break;
+            case CorsairSessionState.Closed:
+                _corsairUnsubscribeForEvents();
+                break;
+        }
+    }
+    
+    private static void CorsairEventCallback(nint context, _CorsairEvent eventData)
+    {
+        if (eventData.id != CorsairEventId.DeviceConnectionStatusChangedEvent)
+        {
+            return;
+        }
+
+        try
+        {
+            if (eventData.eventPointer == 0)
+            {
+                return;
+            }
+
+            _CorsairDeviceConnectionStatusChangedEvent connectionStatusChangedEvent =
+                Marshal.PtrToStructure<_CorsairDeviceConnectionStatusChangedEvent>(eventData.eventPointer)!;
+
+            DeviceConnectionEvent?.Invoke(null, connectionStatusChangedEvent);
+        }catch { /* dont let exception go to sdk */ }
     }
 
     #endregion
@@ -97,7 +134,7 @@ private static void LoadCUESDK()
         _corsairGetSessionDetails = (delegate* unmanaged[Cdecl]<nint, CorsairError>)LoadFunction("CorsairGetSessionDetails");
         _corsairDisconnect = (delegate* unmanaged[Cdecl]<CorsairError>)LoadFunction("CorsairDisconnect");
         _corsairGetDevices = (delegate* unmanaged[Cdecl]<_CorsairDeviceFilter, int, nint, out int, CorsairError>)LoadFunction("CorsairGetDevices");
-        _corsairGetDeviceInfo = (delegate* unmanaged[Cdecl]<string, _CorsairDeviceInfo, CorsairError>)LoadFunction("CorsairGetDeviceInfo");
+        _corsairGetDeviceInfo = (delegate* unmanaged[Cdecl]<string, ref _CorsairDeviceInfo, CorsairError>)LoadFunction("CorsairGetDeviceInfo");
         _corsairGetLedPositions = (delegate* unmanaged[Cdecl]<string, int, nint, out int, CorsairError>)LoadFunction("CorsairGetLedPositions");
         _corsairSetLedColors = (delegate* unmanaged[Cdecl]<string, int, nint, CorsairError>)LoadFunction("CorsairSetLedColors");
         _corsairSetLayerPriority = (delegate* unmanaged[Cdecl]<uint, CorsairError>)LoadFunction("CorsairSetLayerPriority");
@@ -106,6 +143,8 @@ private static void LoadCUESDK()
         _corsairReleaseControl = (delegate* unmanaged[Cdecl]<string, CorsairError>)LoadFunction("CorsairReleaseControl");
         _getDevicePropertyInfo = (delegate* unmanaged[Cdecl]<string, CorsairDevicePropertyId, uint, out CorsairDataType, out CorsairPropertyFlag, CorsairError>)LoadFunction("CorsairGetDevicePropertyInfo");
         _readDeviceProperty = (delegate* unmanaged[Cdecl]<string, CorsairDevicePropertyId, uint, nint, CorsairError>)LoadFunction("CorsairReadDeviceProperty");
+        _corsairSubscribeForEvents = (delegate* unmanaged[Cdecl]<CorsairEventHandler, nint, CorsairError>)LoadFunction("CorsairSubscribeForEvents");
+        _corsairUnsubscribeForEvents = (delegate* unmanaged[Cdecl]<CorsairError>)LoadFunction("CorsairSubscribeForEvents");
     }
 
     private static nint LoadFunction(string function)
@@ -158,7 +197,7 @@ internal static void UnloadCUESDK()
     private static delegate* unmanaged[Cdecl]<nint, CorsairError> _corsairGetSessionDetails;
     private static delegate* unmanaged[Cdecl]<CorsairError> _corsairDisconnect;
     private static delegate* unmanaged[Cdecl]<_CorsairDeviceFilter, int, nint, out int, CorsairError> _corsairGetDevices;
-    private static delegate* unmanaged[Cdecl]<string, _CorsairDeviceInfo, CorsairError> _corsairGetDeviceInfo;
+    private static delegate* unmanaged[Cdecl]<string, ref _CorsairDeviceInfo, CorsairError> _corsairGetDeviceInfo;
     private static delegate* unmanaged[Cdecl]<string, int, nint, out int, CorsairError> _corsairGetLedPositions;
     private static delegate* unmanaged[Cdecl]<string, int, nint, CorsairError> _corsairSetLedColors;
     private static delegate* unmanaged[Cdecl]<uint, CorsairError> _corsairSetLayerPriority;
@@ -167,13 +206,18 @@ internal static void UnloadCUESDK()
     private static delegate* unmanaged[Cdecl]<string, CorsairError> _corsairReleaseControl;
     private static delegate* unmanaged[Cdecl]<string, CorsairDevicePropertyId, uint, out CorsairDataType, out CorsairPropertyFlag, CorsairError> _getDevicePropertyInfo;
     private static delegate* unmanaged[Cdecl]<string, CorsairDevicePropertyId, uint, nint, CorsairError> _readDeviceProperty;
+    private static delegate* unmanaged[Cdecl]<CorsairEventHandler, nint, CorsairError> _corsairSubscribeForEvents;
+    private static delegate* unmanaged[Cdecl]<CorsairError> _corsairUnsubscribeForEvents;
 
     #endregion
 
     internal static CorsairError CorsairConnect()
     {
         if (_corsairConnectPtr == null) throw new RGBDeviceException("The Corsair-SDK is not initialized.");
-        if (IsConnected) throw new RGBDeviceException("The Corsair-SDK is already connected.");
+        if (SessionState is CorsairSessionState.Connecting or CorsairSessionState.Timeout)
+        {
+            return CorsairError.Success;
+        }
         return _corsairConnectPtr(CorsairSessionStateChangedCallback, 0);
     }
 
@@ -197,7 +241,6 @@ internal static CorsairError CorsairGetSessionDetails(out _CorsairSessionDetails
 
     internal static CorsairError CorsairDisconnect()
     {
-        if (!IsConnected) throw new RGBDeviceException("The Corsair-SDK is not connected.");
         return _corsairDisconnect();
     }
 
@@ -220,10 +263,12 @@ internal static CorsairError CorsairGetDevices(_CorsairDeviceFilter filter, out
         }
     }
 
-    internal static CorsairError CorsairGetDeviceInfo(string deviceId, _CorsairDeviceInfo deviceInfo)
+    internal static CorsairError CorsairGetDeviceInfo(string deviceId, out _CorsairDeviceInfo deviceInfo)
     {
         if (!IsConnected) throw new RGBDeviceException("The Corsair-SDK is not connected.");
-        return _corsairGetDeviceInfo(deviceId, deviceInfo);
+
+        deviceInfo = new _CorsairDeviceInfo();
+        return _corsairGetDeviceInfo(deviceId, ref deviceInfo);
     }
 
     internal static CorsairError CorsairGetLedPositions(string deviceId, out _CorsairLedPosition[] ledPositions)
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairDeviceConnectionStatusChangedEvent.cs b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceConnectionStatusChangedEvent.cs
new file mode 100644
index 00000000..bc71d914
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceConnectionStatusChangedEvent.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native;
+
+[StructLayout(LayoutKind.Sequential)]
+public class _CorsairDeviceConnectionStatusChangedEvent
+{
+    /// <summary>
+    /// iCUE-SDK: null terminated Unicode string that contains unique device identifier
+    /// </summary>
+    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = _CUESDK.CORSAIR_STRING_SIZE_M)]
+    internal string? deviceId;
+
+    /// <summary>
+    /// iCUE-SDK: true if connected, false if disconnected
+    /// </summary>
+    [MarshalAs(UnmanagedType.U1)]
+    internal bool isConnected;
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs
index b4c8813d..2fc6e31d 100644
--- a/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs
@@ -12,7 +12,7 @@ namespace RGB.NET.Devices.Corsair.Native;
 /// iCUE-SDK: contains information about device
 /// </summary>
 [StructLayout(LayoutKind.Sequential)]
-internal sealed class _CorsairDeviceInfo
+internal struct _CorsairDeviceInfo
 {
     /// <summary>
     /// iCUE-SDK: enum describing device type
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairEvent.cs b/RGB.NET.Devices.Corsair/Native/_CorsairEvent.cs
new file mode 100644
index 00000000..6f5285ad
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairEvent.cs
@@ -0,0 +1,22 @@
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native;
+
+// ReSharper disable once InconsistentNaming
+/// <summary>
+/// iCUE-SDK: contains information about event id and event data
+/// </summary>
+[StructLayout(LayoutKind.Sequential)]
+internal sealed class _CorsairEvent
+{
+    /// <summary>
+    /// iCUE-SDK: event identifier
+    /// </summary>
+    internal CorsairEventId id;
+
+    /// <summary>
+    /// Points to <see cref="_CorsairDeviceConnectionStatusChangedEvent"/> if _CorsairEvent's id is CEI_DeviceConnectionStatusChangedEvent,
+    /// points to <see cref="_CorsairKeyEvent"/> if _CorsairEvent's id is CEI_KeyEvent
+    /// </summary>
+    internal nint eventPointer;
+}