1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-12 17:48:31 +00:00

Merge pull request #381 from DarthAffe/Development

v2.1
This commit is contained in:
DarthAffe 2024-03-09 12:11:38 +01:00 committed by GitHub
commit 4773e0df74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 869 additions and 44 deletions

View File

@ -14,11 +14,11 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
@ -37,25 +37,25 @@ jobs:
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
- name: Upload a Build Artifact NET6
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET6
path: bin/net6.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET7
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET7
path: bin/net7.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET8
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET8
path: bin/net8.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload Nuget Build Artifact
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-Nugets
path: bin/*nupkg
@ -64,9 +64,3 @@ jobs:
run: dotnet nuget push **\*.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
- name: Symbols Push
run: dotnet nuget push **\*.snupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
- name: Create Tag
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
custom_tag: ${{ steps.versioning.outputs.version }}
tag_prefix: v

View File

@ -10,9 +10,9 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x

View File

@ -13,11 +13,11 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
@ -28,7 +28,7 @@ jobs:
uses: PaulHatch/semantic-version@v4.0.3
with:
short_tags: false
format: "${major}.${minor}.${patch}"
format: "${major}.${minor}.${patch}-prerelease.${increment}"
- name: Restore dependencies
run: dotnet restore
- name: Build
@ -36,25 +36,25 @@ jobs:
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
- name: Upload a Build Artifact NET6
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET6
path: bin/net6.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET7
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET7
path: bin/net7.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET8
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET8
path: bin/net8.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload Nuget Build Artifact
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-Nugets
path: bin/*nupkg

View File

@ -99,5 +99,12 @@ public sealed class E131UpdateQueue : UpdateQueue
return _sequenceNumber++;
}
public override void Dispose()
{
base.Dispose();
_socket.Dispose();
}
#endregion
}

View File

@ -277,6 +277,9 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
try { _LogitechGSDK.LogiLedRestoreLighting(); }
catch { /* at least we tried */ }
try { _LogitechGSDK.LogiLedShutdown(); }
catch { /* at least we tried */ }
try { _LogitechGSDK.UnloadLogitechGSDK(); }
catch { /* at least we tried */ }

View File

@ -34,5 +34,10 @@ public enum NovationDevices
[DeviceId("Launchpad Open")]
[ColorCapability(NovationColorCapabilities.RGB)]
[LedIdMapping(LedIdMappings.Pro)]
LaunchpadCustomFirmware
LaunchpadCustomFirmware,
[DeviceId("LPMiniMK3")]
[ColorCapability(NovationColorCapabilities.RGB)]
[LedIdMapping(LedIdMappings.Current)]
LaunchpadMiniMK3,
}

View File

@ -65,11 +65,10 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider
MidiOutCaps outCaps = OutputDeviceBase.GetDeviceCapabilities(index);
if (outCaps.name == null) continue;
string deviceName = outCaps.name.ToUpperInvariant();
NovationDevices? deviceId = (NovationDevices?)Enum.GetValues(typeof(NovationDevices))
.Cast<Enum>()
.Where(x => x.GetDeviceId() != null)
.FirstOrDefault(x => deviceName.Contains(x.GetDeviceId()!.ToUpperInvariant()));
.FirstOrDefault(x => outCaps.name.Contains(x.GetDeviceId()!, StringComparison.InvariantCultureIgnoreCase));
if (deviceId == null) continue;

View File

@ -141,5 +141,8 @@ internal static class LedMappings
["Key: G9"] = LedId.Keyboard_Programmable9,
["Lighting"] = LedId.Keyboard_Brightness,
["Game Mode"] = LedId.Keyboard_WinLock,
["Num Lock Indicator"] = LedId.Keyboard_IndicatorNumLock,
["Caps Lock Indicator"] = LedId.Keyboard_IndicatorCapsLock,
["Scroll Lock Indicator"] = LedId.Keyboard_IndicatorScrollLock,
};
}

View File

@ -1,42 +1,55 @@
namespace RGB.NET.Devices.Razer;
using System;
namespace RGB.NET.Devices.Razer;
/// <summary>
/// Represents a type of Razer SDK endpoint
/// </summary>
[Flags]
public enum RazerEndpointType
{
/// <summary>
/// No endpoint
/// </summary>
None = 0,
/// <summary>
/// The keyboard endpoint
/// </summary>
Keyboard,
Keyboard = 1 << 0,
/// <summary>
/// The laptop keyboard endpoint, shares the <see cref="Keyboard"/> endpoint but has a different LED layout
/// </summary>
LaptopKeyboard,
LaptopKeyboard = 1 << 1,
/// <summary>
/// The mouse endpoint
/// </summary>
Mouse,
Mouse = 1 << 2,
/// <summary>
/// The headset endpoint
/// </summary>
Headset,
Headset = 1 << 3,
/// <summary>
/// The mousepad endpoint
/// </summary>
Mousepad,
Mousepad = 1 << 4,
/// <summary>
/// The keypad endpoint
/// </summary>
Keypad,
Keypad = 1 << 5,
/// <summary>
/// The Chroma Link endpoint
/// </summary>
ChromaLink,
}
ChromaLink = 1 << 6,
/// <summary>
/// All endpoints
/// </summary>
All = ~None
}

View File

@ -50,7 +50,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
/// <summary>
/// Forces to load the devices represented by the emulator even if they aren't reported to exist.
/// </summary>
public bool LoadEmulatorDevices { get; set; } = false;
public RazerEndpointType LoadEmulatorDevices { get; set; } = RazerEndpointType.None;
private const int VENDOR_ID = 0x1532;
@ -216,6 +216,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x008F, RGBDeviceType.Mouse, "Naga Pro", LedMappings.Mouse, RazerEndpointType.Mouse }, //this is via usb connection
{ 0x0090, RGBDeviceType.Mouse, "Naga Pro", LedMappings.Mouse, RazerEndpointType.Mouse }, //this is via bluetooth connection
{ 0x0091, RGBDeviceType.Mouse, "Viper 8khz", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0093, RGBDeviceType.Mouse, "Naga Classic", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0094, RGBDeviceType.Mouse, "Orochi V2", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0096, RGBDeviceType.Mouse, "Naga X", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0099, RGBDeviceType.Mouse, "Basilisk v3", LedMappings.Mouse, RazerEndpointType.Mouse },
@ -312,21 +313,26 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{
DeviceDefinitions.LoadFilter = loadFilter;
IList<IRGBDevice> devices = base.GetLoadedDevices(loadFilter).ToList();
List<IRGBDevice> devices = base.GetLoadedDevices(loadFilter).ToList();
if (LoadEmulatorDevices)
if (LoadEmulatorDevices != RazerEndpointType.None)
{
if (loadFilter.HasFlag(RGBDeviceType.Keyboard) && devices.All(d => d is not RazerKeyboardRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Keyboard) && (LoadEmulatorDevices.HasFlag(RazerEndpointType.Keyboard) || LoadEmulatorDevices.HasFlag(RazerEndpointType.LaptopKeyboard)) && devices.All(d => d is not RazerKeyboardRGBDevice))
devices.Add(new RazerKeyboardRGBDevice(new RazerKeyboardRGBDeviceInfo("Emulator Keyboard", RazerEndpointType.Keyboard), GetUpdateTrigger(), LedMappings.Keyboard));
if (loadFilter.HasFlag(RGBDeviceType.Mouse) && devices.All(d => d is not RazerMouseRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Mouse) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Mouse) && devices.All(d => d is not RazerMouseRGBDevice))
devices.Add(new RazerMouseRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Mouse, RazerEndpointType.Mouse, "Emulator Mouse"), GetUpdateTrigger(), LedMappings.Mouse));
if (loadFilter.HasFlag(RGBDeviceType.Headset) && devices.All(d => d is not RazerHeadsetRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Headset) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Headset) && devices.All(d => d is not RazerHeadsetRGBDevice))
devices.Add(new RazerHeadsetRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Headset, RazerEndpointType.Headset, "Emulator Headset"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Mousepad) && devices.All(d => d is not RazerMousepadRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Mousepad) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Mousepad) && devices.All(d => d is not RazerMousepadRGBDevice))
devices.Add(new RazerMousepadRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Mousepad, RazerEndpointType.Mousepad, "Emulator Mousepad"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Keypad) && devices.All(d => d is not RazerMousepadRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Keypad) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Keypad) && devices.All(d => d is not RazerMousepadRGBDevice))
devices.Add(new RazerKeypadRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Keypad, RazerEndpointType.Keypad, "Emulator Keypad"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Unknown) && devices.All(d => d is not RazerChromaLinkRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Unknown) && LoadEmulatorDevices.HasFlag(RazerEndpointType.ChromaLink) && devices.All(d => d is not RazerChromaLinkRGBDevice))
devices.Add(new RazerChromaLinkRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Unknown, RazerEndpointType.ChromaLink, "Emulator Chroma Link"), GetUpdateTrigger()));
}

View File

@ -315,6 +315,113 @@ public static class LedMappings
{ LedId.Keyboard_Custom1, SteelSeriesLedId.Power },
};
/// <summary>
/// Gets the mapping for GE78HX keyboards.
/// </summary>
// ReSharper disable once InconsistentNaming
public static LedMapping<SteelSeriesLedId> KeyboardMSIGE78Mapping { get; } = new()
{
{ LedId.Keyboard_Escape, SteelSeriesLedId.Escape },
{ LedId.Keyboard_F1, SteelSeriesLedId.F1 },
{ LedId.Keyboard_F2, SteelSeriesLedId.F2 },
{ LedId.Keyboard_F3, SteelSeriesLedId.F3 },
{ LedId.Keyboard_F4, SteelSeriesLedId.F4 },
{ LedId.Keyboard_F5, SteelSeriesLedId.F5 },
{ LedId.Keyboard_F6, SteelSeriesLedId.F6 },
{ LedId.Keyboard_F7, SteelSeriesLedId.F7 },
{ LedId.Keyboard_F8, SteelSeriesLedId.F8 },
{ LedId.Keyboard_F9, SteelSeriesLedId.F9 },
{ LedId.Keyboard_F10, SteelSeriesLedId.F10 },
{ LedId.Keyboard_F11, SteelSeriesLedId.F11 },
{ LedId.Keyboard_F12, SteelSeriesLedId.F12 },
{ LedId.Keyboard_PrintScreen, SteelSeriesLedId.PrintScreen },
{ LedId.Keyboard_Insert, SteelSeriesLedId.Insert },
{ LedId.Keyboard_Delete, SteelSeriesLedId.Delete },
{ LedId.Keyboard_GraveAccentAndTilde, SteelSeriesLedId.Backqoute },
{ LedId.Keyboard_1, SteelSeriesLedId.Keyboard1 },
{ LedId.Keyboard_2, SteelSeriesLedId.Keyboard2 },
{ LedId.Keyboard_3, SteelSeriesLedId.Keyboard3 },
{ LedId.Keyboard_4, SteelSeriesLedId.Keyboard4 },
{ LedId.Keyboard_5, SteelSeriesLedId.Keyboard5 },
{ LedId.Keyboard_6, SteelSeriesLedId.Keyboard6 },
{ LedId.Keyboard_7, SteelSeriesLedId.Keyboard7 },
{ LedId.Keyboard_8, SteelSeriesLedId.Keyboard8 },
{ LedId.Keyboard_9, SteelSeriesLedId.Keyboard9 },
{ LedId.Keyboard_0, SteelSeriesLedId.Keyboard0 },
{ LedId.Keyboard_MinusAndUnderscore, SteelSeriesLedId.Dash },
{ LedId.Keyboard_EqualsAndPlus, SteelSeriesLedId.Equal },
{ LedId.Keyboard_Backspace, SteelSeriesLedId.Backspace },
{ LedId.Keyboard_Tab, SteelSeriesLedId.Tab },
{ LedId.Keyboard_Q, SteelSeriesLedId.Q },
{ LedId.Keyboard_W, SteelSeriesLedId.W },
{ LedId.Keyboard_E, SteelSeriesLedId.E },
{ LedId.Keyboard_R, SteelSeriesLedId.R },
{ LedId.Keyboard_T, SteelSeriesLedId.T },
{ LedId.Keyboard_Y, SteelSeriesLedId.Y },
{ LedId.Keyboard_U, SteelSeriesLedId.U },
{ LedId.Keyboard_I, SteelSeriesLedId.I },
{ LedId.Keyboard_O, SteelSeriesLedId.O },
{ LedId.Keyboard_P, SteelSeriesLedId.P },
{ LedId.Keyboard_BracketLeft, SteelSeriesLedId.LBracket },
{ LedId.Keyboard_BracketRight, SteelSeriesLedId.RBracket },
{ LedId.Keyboard_Backslash, SteelSeriesLedId.Backslash },
{ LedId.Keyboard_CapsLock, SteelSeriesLedId.Caps },
{ LedId.Keyboard_A, SteelSeriesLedId.A },
{ LedId.Keyboard_S, SteelSeriesLedId.S },
{ LedId.Keyboard_D, SteelSeriesLedId.D },
{ LedId.Keyboard_F, SteelSeriesLedId.F },
{ LedId.Keyboard_G, SteelSeriesLedId.G },
{ LedId.Keyboard_H, SteelSeriesLedId.H },
{ LedId.Keyboard_J, SteelSeriesLedId.J },
{ LedId.Keyboard_K, SteelSeriesLedId.K },
{ LedId.Keyboard_L, SteelSeriesLedId.L },
{ LedId.Keyboard_SemicolonAndColon, SteelSeriesLedId.Semicolon },
{ LedId.Keyboard_ApostropheAndDoubleQuote, SteelSeriesLedId.Quote },
{ LedId.Keyboard_Enter, SteelSeriesLedId.Return },
{ LedId.Keyboard_LeftShift, SteelSeriesLedId.LShift },
{ LedId.Keyboard_Z, SteelSeriesLedId.Z },
{ LedId.Keyboard_X, SteelSeriesLedId.X },
{ LedId.Keyboard_C, SteelSeriesLedId.C },
{ LedId.Keyboard_V, SteelSeriesLedId.V },
{ LedId.Keyboard_B, SteelSeriesLedId.B },
{ LedId.Keyboard_N, SteelSeriesLedId.N },
{ LedId.Keyboard_M, SteelSeriesLedId.M },
{ LedId.Keyboard_CommaAndLessThan, SteelSeriesLedId.Comma },
{ LedId.Keyboard_PeriodAndBiggerThan, SteelSeriesLedId.Period },
{ LedId.Keyboard_SlashAndQuestionMark, SteelSeriesLedId.Slash },
{ LedId.Keyboard_RightShift, SteelSeriesLedId.RShift },
{ LedId.Keyboard_LeftCtrl, SteelSeriesLedId.LCtrl },
{ LedId.Keyboard_LeftGui, SteelSeriesLedId.LWin },
{ LedId.Keyboard_LeftAlt, SteelSeriesLedId.LAlt },
{ LedId.Keyboard_Space, SteelSeriesLedId.Spacebar },
{ LedId.Keyboard_RightAlt, SteelSeriesLedId.RAlt },
{ LedId.Keyboard_NonUsBackslash, SteelSeriesLedId.NonUsBackslash },
{ LedId.Keyboard_RightCtrl, SteelSeriesLedId.RCtrl },
{ LedId.Keyboard_Function, SteelSeriesLedId.Fn },
{ LedId.Keyboard_ArrowUp, SteelSeriesLedId.UpArrow },
{ LedId.Keyboard_ArrowLeft, SteelSeriesLedId.LeftArrow },
{ LedId.Keyboard_ArrowDown, SteelSeriesLedId.DownArrow },
{ LedId.Keyboard_ArrowRight, SteelSeriesLedId.RightArrow },
{ LedId.Keyboard_NumAsterisk, SteelSeriesLedId.KeypadTimes },
{ LedId.Keyboard_NumSlash, SteelSeriesLedId.KeypadDivide },
{ LedId.Logo, SteelSeriesLedId.Power },
{ LedId.Keyboard_NumPlus, SteelSeriesLedId.KeypadPlus },
{ LedId.Keyboard_NumMinus, SteelSeriesLedId.KeypadMinus },
{ LedId.Keyboard_NumLock, SteelSeriesLedId.KeypadNumLock },
{ LedId.Keyboard_Num7, SteelSeriesLedId.Keypad7 },
{ LedId.Keyboard_Num8, SteelSeriesLedId.Keypad8 },
{ LedId.Keyboard_Num9, SteelSeriesLedId.Keypad9 },
{ LedId.Keyboard_Num4, SteelSeriesLedId.Keypad4 },
{ LedId.Keyboard_Num5, SteelSeriesLedId.Keypad5 },
{ LedId.Keyboard_Num6, SteelSeriesLedId.Keypad6 },
{ LedId.Keyboard_Num1, SteelSeriesLedId.Keypad1 },
{ LedId.Keyboard_Num2, SteelSeriesLedId.Keypad2 },
{ LedId.Keyboard_Num3, SteelSeriesLedId.Keypad3 },
{ LedId.Keyboard_Num0, SteelSeriesLedId.Keypad0 },
{ LedId.Keyboard_NumPeriodAndDelete, SteelSeriesLedId.KeypadPeriod },
{ LedId.Keyboard_NumEnter, SteelSeriesLedId.KeypadEnter },
};
/// <summary>
/// Gets the mapping for one-zone mice.
/// </summary>

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.SteelSeries.API;
@ -76,7 +76,9 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
{ 0x1600, RGBDeviceType.Keyboard, "Apex M800", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1610, RGBDeviceType.Keyboard, "Apex Pro", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1614, RGBDeviceType.Keyboard, "Apex Pro TKL", LedMappings.KeyboardTklMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x2036, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x2036, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x113A, RGBDeviceType.Keyboard, "MSI GE78HX", LedMappings.KeyboardMSIGE78Mapping, SteelSeriesDeviceType.PerKey },
{ 0x1122, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
//Headsets
{ 0x12AA, RGBDeviceType.Headset, "Arctis 5", LedMappings.HeadsetTwoZone, SteelSeriesDeviceType.TwoZone },

View File

@ -0,0 +1,33 @@
using System.Net.Http;
using System.Net.Http.Json;
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Partial implementation of the WLED-JSON-API
/// </summary>
public static class WledAPI
{
/// <summary>
/// Gets the data returned by the 'info' endpoint of the WLED-device.
/// </summary>
/// <param name="address">The address of the device to request data from.</param>
/// <returns>The data returned by the WLED-device.</returns>
public static WledInfo? Info(string address)
{
if (string.IsNullOrEmpty(address)) return null;
using HttpClient client = new();
try
{
return client.Send(new HttpRequestMessage(HttpMethod.Get, $"http://{address}/json/info"))
.Content
.ReadFromJsonAsync<WledInfo>()
.Result;
}
catch
{
return null;
}
}
}

View File

@ -0,0 +1,156 @@
// ReSharper disable InconsistentNaming
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace RGB.NET.Devices.WLED;
public class WledInfo
{
[JsonPropertyName("ver")]
public string Version { get; set; } = "";
[JsonPropertyName("vid")]
public uint BuildId { get; set; }
[JsonPropertyName("leds")]
public LedsInfo Leds { get; set; } = new();
[JsonPropertyName("str")]
public bool SyncReceive { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("udpport")]
public ushort UDPPort { get; set; }
[JsonPropertyName("live")]
public bool IsLive { get; set; }
[JsonPropertyName("liveseg")]
public short MainSegment { get; set; }
[JsonPropertyName("lm")]
public string RealtimeDataSource { get; set; } = "";
[JsonPropertyName("lip")]
public string RealtimeDataSourceIpAddress { get; set; } = "";
[JsonPropertyName("ws")]
public byte ConnectedWebSocketCount { get; set; }
[JsonPropertyName("fxcount")]
public byte EffectCount { get; set; }
[JsonPropertyName("palcount")]
public short PaletteCount { get; set; }
[JsonPropertyName("maps")]
public List<Map> LedMaps { get; set; } = [];
[JsonPropertyName("wifi")]
public Wifi WifiInfo { get; set; } = new();
[JsonPropertyName("fs")]
public Fs FilesystemInfo { get; set; } = new();
[JsonPropertyName("ndc")]
public short DiscoveredDeviceCount { get; set; }
[JsonPropertyName("arch")]
public string PlatformName { get; set; } = "";
[JsonPropertyName("core")]
public string ArduinoCoreVersion { get; set; } = "";
[JsonPropertyName("freeheap")]
public uint FreeHeap { get; set; }
[JsonPropertyName("uptime")]
public uint Uptime { get; set; }
[JsonPropertyName("time")]
public string Time { get; set; } = "";
[JsonPropertyName("brand")]
public string Brand { get; set; } = "";
[JsonPropertyName("product")]
public string Product { get; set; } = "";
[JsonPropertyName("ip")]
public string IpAddress { get; set; } = "";
public class LedsInfo
{
[JsonPropertyName("count")]
public ushort Count { get; set; }
[JsonPropertyName("pwr")]
public ushort PowerUsage { get; set; }
[JsonPropertyName("fps")]
public ushort RefreshRate { get; set; }
[JsonPropertyName("maxpwr")]
public ushort MaxPower { get; set; }
[JsonPropertyName("maxseg")]
public byte MaxSegments { get; set; }
[JsonPropertyName("matrix")]
public MatrixDims? Matrix { get; set; }
[JsonPropertyName("seglc")]
public List<byte> SegmentLightCapabilities { get; set; } = [];
[JsonPropertyName("lc")]
public byte CombinedSegmentLightCapabilities { get; set; }
}
public class Map
{
[JsonPropertyName("id")]
public byte Id { get; set; }
[JsonPropertyName("n")]
public string Name { get; set; } = "";
}
public class Wifi
{
[JsonPropertyName("bssid")]
public string BSSID { get; set; } = "";
[JsonPropertyName("rssi")]
public long RSSI { get; set; }
[JsonPropertyName("signal")]
public byte SignalQuality { get; set; }
[JsonPropertyName("channel")]
public int Channel { get; set; }
}
public class Fs
{
[JsonPropertyName("u")]
public uint UsedSpace { get; set; }
[JsonPropertyName("t")]
public uint TotalSpace { get; set; }
[JsonPropertyName("pmt")]
public ulong LastPresetsJsonModificationTime { get; set; }
}
public class MatrixDims
{
[JsonPropertyName("w")]
public ushort Width { get; set; }
[JsonPropertyName("h")]
public ushort Height { get; set; }
}
}

View File

@ -0,0 +1,8 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Represents a WLED-device.
/// </summary>
internal interface IWledRGBDevice : IRGBDevice;

View File

@ -0,0 +1,11 @@
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Represents the data used to create a WLED-device.
/// </summary>
public interface IWledDeviceDefinition
{
string Address { get; }
string? Manufacturer { get; }
string? Model { get; }
}

View File

@ -0,0 +1,102 @@
using System;
using System.Net.Sockets;
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents the update-queue performing updates for WLED devices.
/// </summary>
internal sealed class WledDeviceUpdateQueue : UpdateQueue
{
#region Properties & Fields
/// <summary>
/// The UDP-Connection used to send data.
/// </summary>
private readonly UdpClient _socket;
/// <summary>
/// The buffer the UDP-data is stored in.
/// </summary>
private byte[] _buffer;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledDeviceUpdateQueue"/> class.
/// </summary>
/// <param name="updateTrigger">The update trigger used by this queue.</param>
/// <param name="deviceType">The device type used to identify the device.</param>
public WledDeviceUpdateQueue(IDeviceUpdateTrigger updateTrigger, string address, int port, int ledCount)
: base(updateTrigger)
{
_buffer = new byte[2 + (ledCount * 3)];
_buffer[0] = 2; // protocol: DRGB
_buffer[1] = 2; // Timeout 2s
_socket = new UdpClient();
_socket.Connect(address, port);
}
#endregion
#region Methods
/// <inheritdoc />
protected override void OnUpdate(object? sender, CustomUpdateData customData)
{
try
{
if (customData[CustomUpdateDataIndex.HEARTBEAT] as bool? ?? false)
Update(Array.Empty<(object key, Color color)>());
else
base.OnUpdate(sender, customData);
}
catch (Exception ex)
{
WledDeviceProvider.Instance.Throw(ex);
}
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{
Span<byte> data = _buffer.AsSpan()[2..];
foreach ((object key, Color color) in dataSet)
{
int ledIndex = (int)key;
int offset = (ledIndex * 3);
data[offset] = color.GetR();
data[offset + 1] = color.GetG();
data[offset + 2] = color.GetB();
}
_socket.Send(_buffer);
return true;
}
catch (Exception ex)
{
WledDeviceProvider.Instance.Throw(ex);
}
return false;
}
/// <inheritdoc />
public override void Dispose()
{
base.Dispose();
_socket.Dispose();
_buffer = [];
}
#endregion
}

View File

@ -0,0 +1,39 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc cref="AbstractRGBDevice{WledRGBDeviceInfo}" />
/// <inheritdoc cref="IWledRGBDevice" />
/// <summary>
/// Represents a WLED-device.
/// </summary>
public sealed class WledRGBDevice : AbstractRGBDevice<WledRGBDeviceInfo>, IWledRGBDevice, ILedStripe
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledRGBDevice"/> class.
/// </summary>
internal WledRGBDevice(WledRGBDeviceInfo info, string address, IDeviceUpdateTrigger updateTrigger)
: base(info, new WledDeviceUpdateQueue(updateTrigger, address, info.Info.UDPPort, info.Info.Leds.Count))
{
InitializeLayout();
RequiresFlush = true;
}
#endregion
#region Methods
private void InitializeLayout()
{
for (int i = 0; i < DeviceInfo.Info.Leds.Count; i++)
AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10));
}
/// <inheritdoc />
protected override object GetLedCustomData(LedId ledId) => ledId - LedId.LedStripe1;
#endregion
}

View File

@ -0,0 +1,52 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents a generic information for a WLED-<see cref="T:RGB.NET.Core.IRGBDevice" />.
/// </summary>
public sealed class WledRGBDeviceInfo : IRGBDeviceInfo
{
#region Properties & Fields
/// <inheritdoc />
public RGBDeviceType DeviceType => RGBDeviceType.LedStripe;
/// <inheritdoc />
public string DeviceName { get; }
/// <inheritdoc />
public string Manufacturer { get; }
/// <inheritdoc />
public string Model { get; }
/// <inheritdoc />
public object? LayoutMetadata { get; set; }
/// <summary>
/// Gets some info returned by the WLED-device.
/// </summary>
public WledInfo Info { get; }
#endregion
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="WledRGBDeviceInfo"/>.
/// </summary>
/// <param name="manufacturer">The manufacturer of the device.</param>
/// <param name="model">The represented device model.</param>
internal WledRGBDeviceInfo(WledInfo info, string? manufacturer, string? model)
{
this.Info = info;
this.Manufacturer = manufacturer ?? info.Brand;
this.Model = model ?? info.Name;
DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);
}
#endregion
}

View File

@ -0,0 +1,18 @@
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
public class WledDeviceDefinition(string address, string? manufacturer = null, string? model = null) : IWledDeviceDefinition
{
#region Properties & Fields
/// <inheritdoc />
public string Address { get; } = address;
/// <inheritdoc />
public string? Manufacturer { get; } = manufacturer;
/// <inheritdoc />
public string? Model { get; } = model;
#endregion
}

View File

@ -0,0 +1,82 @@
[RGB.NET](https://github.com/DarthAffe/RGB.NET) Device-Provider-Package for [WLED](https://kno.wled.ge/)-devices.
## Usage
This provider does not load anything by default and requires additional configuration to work.
```csharp
// Add as many WLED-devices as you like
WledDeviceProvider.Instance.AddDeviceDefinition(new WledDeviceDefinition("<hostname>"));
surface.Load(WledDeviceProvider.Instance);
```
You can also override the manufacturer and device model in the DeviceDefinition.
# Required SDK
This provider does not require an additional SDK.
UDP realtime needs to be enabled on the WLED device.
# Automatic device discovery
Due to the requirement of an additional dependency and the requirement to be able to configure devices manually anywy automatic discovery is not part of the provider.
Using the nuget `Tmds.MDns` you can use the following Helper to do this:
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Tmds.MDns;
namespace RGB.NET.Devices.WLED;
public static class WledDiscoveryHelper
{
/// <summary>
/// Searches for WLED devices and returns a list of devices found.
/// </summary>
/// <param name="waitFor">The time the discovery is waiting for responses. Choose this as short as possible as the method is blocking </param>
/// <param name="maxDevices">The maximum amount of devices that are expected in the network. The discovery will stop early if the given amount of devices is found.</param>
/// <returns>A list of addresses and device-infos.</returns>
public static IEnumerable<(string address, WledInfo info)> DiscoverDevices(int waitFor = 500, int maxDevices = -1)
{
List<(string address, WledInfo info)> devices = [];
using ManualResetEventSlim waitEvent = new(false);
int devicesToDetect = maxDevices <= 0 ? int.MaxValue : maxDevices;
ServiceBrowser mdns = new();
mdns.ServiceAdded += OnServiceAdded;
mdns.StartBrowse("_http._tcp");
waitEvent.Wait(TimeSpan.FromMilliseconds(waitFor));
mdns.StopBrowse();
mdns.ServiceAdded -= OnServiceAdded;
return devices;
void OnServiceAdded(object? sender, ServiceAnnouncementEventArgs args)
{
string address = args.Announcement.Addresses.FirstOrDefault()?.ToString() ?? string.Empty;
if (!string.IsNullOrWhiteSpace(address))
{
WledInfo? info = null;
try
{
info = WledAPI.Info(address);
}
catch { }
if (info != null)
{
devices.Add((address, info));
if (--devicesToDetect <= 0)
waitEvent.Set();
}
}
}
}
}
```

View File

@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Authors>Darth Affe</Authors>
<Company>Wyrez</Company>
<Language>en-US</Language>
<NeutralLanguage>en-US</NeutralLanguage>
<Title>RGB.NET.Devices.WLED</Title>
<AssemblyName>RGB.NET.Devices.WLED</AssemblyName>
<AssemblyTitle>RGB.NET.Devices.WLED</AssemblyTitle>
<PackageId>RGB.NET.Devices.WLED</PackageId>
<RootNamespace>RGB.NET.Devices.WLED</RootNamespace>
<Description>WLED-Device-Implementations of RGB.NET</Description>
<Summary>WLED-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals</Summary>
<Copyright>Copyright © Darth Affe 2024</Copyright>
<PackageCopyright>Copyright © Darth Affe 2024</PackageCopyright>
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/DarthAffe/RGB.NET</PackageProjectUrl>
<PackageLicenseExpression>LGPL-2.1-only</PackageLicenseExpression>
<RepositoryType>Github</RepositoryType>
<RepositoryUrl>https://github.com/DarthAffe/RGB.NET</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageReleaseNotes></PackageReleaseNotes>
<Version>0.0.1</Version>
<AssemblyVersion>0.0.1</AssemblyVersion>
<FileVersion>0.0.1</FileVersion>
<OutputPath>..\bin\</OutputPath>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IncludeSource>True</IncludeSource>
<IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Optimize>true</Optimize>
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
<DefineConstants>RELEASE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Content Include="..\Resources\icon.png" Link="icon.png" Pack="true" PackagePath="\" />
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RGB.NET.Core\RGB.NET.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=api/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generic/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,113 @@
// ReSharper disable MemberCanBePrivate.Global
using System;
using System.Collections.Generic;
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents a device provider responsible for WS2812B- and WS2811-Led-devices.
/// </summary>
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public sealed class WledDeviceProvider : AbstractRGBDeviceProvider
{
#region Constants
private const int HEARTBEAT_TIMER = 250;
#endregion
#region Properties & Fields
// ReSharper disable once InconsistentNaming
private static readonly object _lock = new();
private static WledDeviceProvider? _instance;
/// <summary>
/// Gets the singleton <see cref="WledDeviceProvider"/> instance.
/// </summary>
public static WledDeviceProvider Instance
{
get
{
lock (_lock)
return _instance ?? new WledDeviceProvider();
}
}
/// <summary>
/// Gets a list of all defined device-definitions.
/// </summary>
public List<IWledDeviceDefinition> DeviceDefinitions { get; } = [];
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledDeviceProvider"/> class.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if this constructor is called even if there is already an instance of this class.</exception>
public WledDeviceProvider()
{
lock (_lock)
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WledDeviceProvider)}");
_instance = this;
}
}
#endregion
#region Methods
/// <summary>
/// Adds the specified <see cref="IWledDeviceDefinition" /> to this device-provider.
/// </summary>
/// <param name="deviceDefinition">The <see cref="IWledDeviceDefinition"/> to add.</param>
public void AddDeviceDefinition(IWledDeviceDefinition deviceDefinition) => DeviceDefinitions.Add(deviceDefinition);
/// <inheritdoc />
protected override void InitializeSDK() { }
/// <inheritdoc />
protected override IEnumerable<IRGBDevice> LoadDevices()
{
int i = 0;
foreach (IWledDeviceDefinition deviceDefinition in DeviceDefinitions)
{
IDeviceUpdateTrigger updateTrigger = GetUpdateTrigger(i++);
WledRGBDevice? device = CreateWledDevice(deviceDefinition, updateTrigger);
if (device != null)
yield return device;
}
}
private static WledRGBDevice? CreateWledDevice(IWledDeviceDefinition deviceDefinition, IDeviceUpdateTrigger updateTrigger)
{
WledInfo? wledInfo = WledAPI.Info(deviceDefinition.Address);
if (wledInfo == null) return null;
return new WledRGBDevice(new WledRGBDeviceInfo(wledInfo, deviceDefinition.Manufacturer, deviceDefinition.Model), deviceDefinition.Address, updateTrigger);
}
protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit) { HeartbeatTimer = HEARTBEAT_TIMER };
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
lock (_lock)
{
base.Dispose(disposing);
DeviceDefinitions.Clear();
_instance = null;
}
}
#endregion
}

View File

@ -49,6 +49,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.OpenRGB", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.Corsair_Legacy", "RGB.NET.Devices.Corsair_Legacy\RGB.NET.Devices.Corsair_Legacy.csproj", "{66AF690C-27A1-4097-AC53-57C0ED89E286}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.WLED", "RGB.NET.Devices.WLED\RGB.NET.Devices.WLED.csproj", "{C533C5EA-66A8-4826-A814-80791E7593ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -139,6 +141,10 @@ Global
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Release|Any CPU.Build.0 = Release|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -161,6 +167,7 @@ Global
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F} = {92D7C263-D4C9-4D26-93E2-93C1F9C2CD16}
{F29A96E5-CDD0-469F-A871-A35A7519BC49} = {D13032C6-432E-4F43-8A32-071133C22B16}
{66AF690C-27A1-4097-AC53-57C0ED89E286} = {D13032C6-432E-4F43-8A32-071133C22B16}
{C533C5EA-66A8-4826-A814-80791E7593ED} = {D13032C6-432E-4F43-8A32-071133C22B16}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F222AD4-1F9E-4AAB-9D69-D62372D4C1BA}