diff --git a/ControlPad/Arduino/ArduinoController.cs b/ControlPad/Arduino/ArduinoController.cs
index 853eeee..26f76a3 100644
--- a/ControlPad/Arduino/ArduinoController.cs
+++ b/ControlPad/Arduino/ArduinoController.cs
@@ -61,7 +61,7 @@ public static void Initialize(MainWindow mainWindow, EventHandler eventHandler)
private static async Task TryOpenAsync()
{
- string? port = await Task.Run(() => ArduinoPortFinder.FindFirstArduinoPort());
+ var (port, deviceId) = await Task.Run(() => ArduinoPortFinder.FindFirstArduinoPort());
if (port == null)
{
await _mainWindow.Dispatcher.InvokeAsync(() =>
@@ -99,11 +99,16 @@ await _mainWindow.Dispatcher.InvokeAsync(() =>
_readCts = new CancellationTokenSource();
_ = Task.Run(() => ReadLoopAsync(sp, _readCts.Token));
+ string? serial = ArduinoPortFinder.ExtractSerial(deviceId);
+ BadgeType badge = await SubscriptionService.GetBadgeTypeAsync(serial);
+ _lastBadgeType = badge;
+
await _mainWindow.Dispatcher.InvokeAsync(() =>
{
_mainWindow.BoardDisconnectedInfoBar.IsOpen = false;
if (_mainWindow.NVI_Home.IsActive) _mainWindow.MainContentFrame.Navigate(_mainWindow._homeUserControl);
_mainWindow.NVI_EditMode.Visibility = Visibility.Visible;
+ _mainWindow.UpdateBadgeType(badge);
IsConnected = true;
});
}
diff --git a/ControlPad/Arduino/ArduinoPortFinder.cs b/ControlPad/Arduino/ArduinoPortFinder.cs
index d1868f9..5a0ee54 100644
--- a/ControlPad/Arduino/ArduinoPortFinder.cs
+++ b/ControlPad/Arduino/ArduinoPortFinder.cs
@@ -12,8 +12,8 @@ public static class ArduinoPortFinder
"VID_0403" // FTDI-basierte Klone (ältere Duemilanove usw.)
};
- /// Gibt z. B. "COM7" zurück oder null, wenn kein Arduino gefunden wurde.
- public static string FindFirstArduinoPort()
+ /// Returns the COM port and PNPDeviceID, or (null, null) if no Arduino was found.
+ public static (string? port, string? deviceId) FindFirstArduinoPort()
{
foreach (string port in SerialPort.GetPortNames()) // 1. alle Ports holen
{
@@ -28,14 +28,25 @@ public static string FindFirstArduinoPort()
// 2a) Originale melden sich mit "Arduino XY (COMn)"
if (name.IndexOf("Arduino", StringComparison.OrdinalIgnoreCase) >= 0)
- return port;
+ return (port, id);
// 2b) Klone: auf Vendor-ID prüfen
if (Array.Exists(KnownVids, vid =>
id.IndexOf(vid, StringComparison.OrdinalIgnoreCase) >= 0))
- return port;
+ return (port, id);
}
}
- return null; // nichts gefunden
+ return (null, null); // nichts gefunden
+ }
+
+ /// Extracts the serial number segment from a PNPDeviceID string (e.g. USB\VID_2341&PID_0043\SERIAL).
+ public static string? ExtractSerial(string? pnpDeviceId)
+ {
+ if (string.IsNullOrEmpty(pnpDeviceId))
+ return null;
+
+ // PNPDeviceID format: USB\VID_XXXX&PID_XXXX\SERIAL
+ var parts = pnpDeviceId.Split('\\');
+ return parts.Length >= 3 ? parts[2] : null;
}
}
diff --git a/ControlPad/SubscriptionService.cs b/ControlPad/SubscriptionService.cs
new file mode 100644
index 0000000..f887d7d
--- /dev/null
+++ b/ControlPad/SubscriptionService.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net.Http;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace ControlPad
+{
+ public static class SubscriptionService
+ {
+ private const string SubscriptionsUrl =
+ "https://raw.githubusercontent.com/ControlPad/App/main/subscriptions.json";
+
+ private static readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(10) };
+ private static readonly Dictionary _cache = new(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// Fetches the subscriptions file from GitHub and returns the badge type
+ /// for the given device serial number.
+ ///
+ public static async Task GetBadgeTypeAsync(string? serial)
+ {
+ if (string.IsNullOrEmpty(serial))
+ return BadgeType.None;
+
+ if (_cache.TryGetValue(serial, out var cached))
+ return cached;
+
+ try
+ {
+ string json = await _httpClient.GetStringAsync(SubscriptionsUrl);
+ var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
+ var data = JsonSerializer.Deserialize(json, options);
+ if (data?.Subscriptions == null)
+ return BadgeType.None;
+
+ foreach (var entry in data.Subscriptions)
+ {
+ if (Enum.IsDefined(typeof(BadgeType), entry.BadgeType))
+ {
+ var badge = (BadgeType)entry.BadgeType;
+ _cache[entry.SerialNumber] = badge;
+
+ if (string.Equals(entry.SerialNumber, serial, StringComparison.OrdinalIgnoreCase))
+ return badge;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Subscription fetch failed: {ex.Message}");
+ }
+
+ return BadgeType.None;
+ }
+
+ private class SubscriptionsData
+ {
+ public List? Subscriptions { get; set; }
+ }
+
+ private class SubscriptionEntry
+ {
+ public string SerialNumber { get; set; } = "";
+ public int BadgeType { get; set; }
+ }
+ }
+}
diff --git a/subscriptions.json b/subscriptions.json
new file mode 100644
index 0000000..59ecbf4
--- /dev/null
+++ b/subscriptions.json
@@ -0,0 +1,3 @@
+{
+ "subscriptions": []
+}