|
| 1 | +# G Hub WebSocket Explorer - FFBArcadePlugin |
| 2 | +# Connects to lghub_agent.exe WebSocket and explores available commands |
| 3 | +# Requires: G Hub running, PowerShell 5.1+ |
| 4 | + |
| 5 | +Add-Type -AssemblyName System.Net.WebSockets |
| 6 | + |
| 7 | +$ws = New-Object System.Net.WebSockets.ClientWebSocket |
| 8 | +$ws.Options.AddSubProtocol("json") |
| 9 | + |
| 10 | +$uri = [Uri]"ws://localhost:9010" |
| 11 | +$cts = New-Object System.Threading.CancellationTokenSource |
| 12 | + |
| 13 | +Write-Host "" |
| 14 | +Write-Host "=== G Hub WebSocket Explorer ===" |
| 15 | +Write-Host "Connecting to $uri..." |
| 16 | +Write-Host "" |
| 17 | + |
| 18 | +try { |
| 19 | + $task = $ws.ConnectAsync($uri, $cts.Token) |
| 20 | + if (-not $task.Wait(5000)) { |
| 21 | + Write-Host "ERROR: Connection timeout (5s)" |
| 22 | + Read-Host "Appuie sur Entree" |
| 23 | + exit 1 |
| 24 | + } |
| 25 | + if ($task.IsFaulted) { throw $task.Exception } |
| 26 | + Write-Host "Connected! State: $($ws.State)" |
| 27 | +} catch { |
| 28 | + Write-Host "Connection failed: $_" |
| 29 | + Write-Host "" |
| 30 | + Write-Host "G Hub is running? Check if lghub_agent.exe is in Task Manager." |
| 31 | + Read-Host "Appuie sur Entree" |
| 32 | + exit 1 |
| 33 | +} |
| 34 | + |
| 35 | +function Send-WS($json) { |
| 36 | + $bytes = [System.Text.Encoding]::UTF8.GetBytes($json) |
| 37 | + $segment = New-Object System.ArraySegment[byte](,$bytes) |
| 38 | + $task = $ws.SendAsync($segment, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $cts.Token) |
| 39 | + $task.Wait(3000) | Out-Null |
| 40 | +} |
| 41 | + |
| 42 | +function Recv-WS { |
| 43 | + $buffer = New-Object byte[] 131072 |
| 44 | + $result = "" |
| 45 | + $timeoutCts = New-Object System.Threading.CancellationTokenSource |
| 46 | + $timeoutCts.CancelAfter(3000) # 3s timeout per receive |
| 47 | + |
| 48 | + try { |
| 49 | + do { |
| 50 | + $segment = New-Object System.ArraySegment[byte](,$buffer) |
| 51 | + $task = $ws.ReceiveAsync($segment, $timeoutCts.Token) |
| 52 | + $task.Wait() | Out-Null |
| 53 | + $recv = $task.Result |
| 54 | + $result += [System.Text.Encoding]::UTF8.GetString($buffer, 0, $recv.Count) |
| 55 | + } while (-not $recv.EndOfMessage) |
| 56 | + return $result |
| 57 | + } catch { |
| 58 | + if ($result.Length -gt 0) { return $result } |
| 59 | + return $null |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +function Test-Endpoint($id, $verb, $path, $payload) { |
| 64 | + Write-Host "--- [$id] $verb $path ---" |
| 65 | + |
| 66 | + $msg = @{ msgId = "$id"; verb = $verb; path = $path } |
| 67 | + if ($payload) { $msg.payload = $payload } |
| 68 | + $json = $msg | ConvertTo-Json -Compress -Depth 5 |
| 69 | + |
| 70 | + Send-WS $json |
| 71 | + $resp = Recv-WS |
| 72 | + |
| 73 | + if ($resp) { |
| 74 | + Write-Host $resp |
| 75 | + } else { |
| 76 | + Write-Host " (no response / timeout)" |
| 77 | + } |
| 78 | + Write-Host "" |
| 79 | +} |
| 80 | + |
| 81 | +$id = 1 |
| 82 | + |
| 83 | +# ============================================================ |
| 84 | +# PHASE 1: Device discovery |
| 85 | +# ============================================================ |
| 86 | +Write-Host "" |
| 87 | +Write-Host "========================================" |
| 88 | +Write-Host "PHASE 1: Device Discovery" |
| 89 | +Write-Host "========================================" |
| 90 | +Write-Host "" |
| 91 | + |
| 92 | +Test-Endpoint ($id++) "GET" "/devices/list" $null |
| 93 | +Test-Endpoint ($id++) "GET" "/devices/state" $null |
| 94 | +Test-Endpoint ($id++) "GET" "/api/v1/devices/list" $null |
| 95 | + |
| 96 | +# ============================================================ |
| 97 | +# PHASE 2: Integration registration |
| 98 | +# ============================================================ |
| 99 | +Write-Host "========================================" |
| 100 | +Write-Host "PHASE 2: Integration Registration" |
| 101 | +Write-Host "========================================" |
| 102 | +Write-Host "" |
| 103 | + |
| 104 | +$regPayload = @{ |
| 105 | + integrationIdentifier = "ffb_arcade_plugin" |
| 106 | + name = "FFB Arcade Plugin" |
| 107 | + author = "FFBArcade" |
| 108 | + description = "LED control for racing wheels" |
| 109 | + manualRegistration = $true |
| 110 | +} |
| 111 | +Test-Endpoint ($id++) "SET" "/api/v1/integration/register" $regPayload |
| 112 | + |
| 113 | +# Try activation with different SDK types |
| 114 | +$sdkTypes = @("ACTION", "LED", "LIGHTSYNC", "STEERING", "WHEEL", "LIGHTING", "SCREEN_SAMPLER") |
| 115 | +foreach ($st in $sdkTypes) { |
| 116 | + $actPayload = @{ |
| 117 | + integrationIdentifier = "ffb_arcade_plugin" |
| 118 | + sdkType = $st |
| 119 | + } |
| 120 | + Test-Endpoint ($id++) "SET" "/api/v1/integration/activate" $actPayload |
| 121 | +} |
| 122 | + |
| 123 | +# ============================================================ |
| 124 | +# PHASE 3: Explore lighting/LED endpoints |
| 125 | +# ============================================================ |
| 126 | +Write-Host "========================================" |
| 127 | +Write-Host "PHASE 3: Lighting Endpoints" |
| 128 | +Write-Host "========================================" |
| 129 | +Write-Host "" |
| 130 | + |
| 131 | +$lightingPaths = @( |
| 132 | + @("GET", "/lighting/state"), |
| 133 | + @("GET", "/lighting/devices"), |
| 134 | + @("GET", "/lighting/effects"), |
| 135 | + @("GET", "/api/v1/lighting/state"), |
| 136 | + @("GET", "/api/v1/lighting/devices"), |
| 137 | + @("GET", "/lightsync/state"), |
| 138 | + @("GET", "/lightsync/devices"), |
| 139 | + @("GET", "/profiles/current"), |
| 140 | + @("GET", "/profiles/list"), |
| 141 | + @("GET", "/api/v1/profiles/current"), |
| 142 | + @("GET", "/api/v1/profiles/list"), |
| 143 | + @("GET", "/features/list"), |
| 144 | + @("GET", "/api/v1/features/list"), |
| 145 | + @("GET", "/steering/state"), |
| 146 | + @("GET", "/wheel/state"), |
| 147 | + @("GET", "/sdk/state"), |
| 148 | + @("GET", "/api/v1/sdk/state") |
| 149 | +) |
| 150 | + |
| 151 | +foreach ($ep in $lightingPaths) { |
| 152 | + Test-Endpoint ($id++) $ep[0] $ep[1] $null |
| 153 | +} |
| 154 | + |
| 155 | +# ============================================================ |
| 156 | +# PHASE 4: Try SET commands for LED control |
| 157 | +# ============================================================ |
| 158 | +Write-Host "========================================" |
| 159 | +Write-Host "PHASE 4: LED Control Attempts" |
| 160 | +Write-Host "========================================" |
| 161 | +Write-Host "" |
| 162 | + |
| 163 | +# Try setting lighting on various paths |
| 164 | +$ledPayload = @{ red = 0; green = 100; blue = 0 } |
| 165 | +Test-Endpoint ($id++) "SET" "/lighting/color" $ledPayload |
| 166 | +Test-Endpoint ($id++) "SET" "/api/v1/lighting/color" $ledPayload |
| 167 | + |
| 168 | +$zonePayload = @{ deviceType = "steering_wheel"; zone = 0; red = 0; green = 100; blue = 0 } |
| 169 | +Test-Endpoint ($id++) "SET" "/lighting/zone" $zonePayload |
| 170 | + |
| 171 | +$ledPayload2 = @{ leds = 31; device = "steering_wheel" } |
| 172 | +Test-Endpoint ($id++) "SET" "/steering/leds" $ledPayload2 |
| 173 | +Test-Endpoint ($id++) "SET" "/wheel/leds" $ledPayload2 |
| 174 | + |
| 175 | +# ============================================================ |
| 176 | +# Cleanup |
| 177 | +# ============================================================ |
| 178 | +Write-Host "========================================" |
| 179 | +Write-Host "Done! Copy-paste ALL output above." |
| 180 | +Write-Host "========================================" |
| 181 | + |
| 182 | +try { |
| 183 | + $ws.CloseAsync([System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure, "done", $cts.Token).Wait(3000) | Out-Null |
| 184 | +} catch { } |
| 185 | + |
| 186 | +Read-Host "Appuie sur Entree pour fermer" |
0 commit comments