Spaces:
Running
Running
| """ | |
| modules/bt_devices.py — Phase 4: Bluetooth disconnect by device name (best-effort). | |
| Windows Bluetooth pairing/unpairing is not stable without additional tooling. | |
| We provide a real "disconnect" approximation by disabling the matching Bluetooth PnP device. | |
| This often requires admin. | |
| """ | |
| from __future__ import annotations | |
| import subprocess | |
| from dataclasses import dataclass | |
| class BTResult: | |
| ok: bool | |
| message: str | |
| def _ps(cmd: str) -> subprocess.CompletedProcess[str]: | |
| return subprocess.run( | |
| ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", cmd], | |
| capture_output=True, | |
| text=True, | |
| shell=False, | |
| ) | |
| def disconnect(name_substring: str) -> BTResult: | |
| s = (name_substring or "").strip() | |
| if not s: | |
| return BTResult(False, "Missing device name.") | |
| cmd = ( | |
| "try { " | |
| f"$d = Get-PnpDevice -Class Bluetooth -ErrorAction SilentlyContinue | Where-Object {{$_.FriendlyName -like '*{s}*'}} | Select-Object -First 1; " | |
| "if($null -eq $d){ 'NOTFOUND' } else { Disable-PnpDevice -InstanceId $d.InstanceId -Confirm:$false -ErrorAction Stop; 'OK' }" | |
| "} catch { 'FAIL:' + $_.Exception.Message }" | |
| ) | |
| r = _ps(cmd) | |
| out = (r.stdout or "").strip() | |
| if out == "OK": | |
| return BTResult(True, "Bluetooth device disconnected (disabled).") | |
| if out == "NOTFOUND": | |
| return BTResult(False, "Bluetooth device not found.") | |
| if "access is denied" in out.lower(): | |
| return BTResult(False, "Bluetooth disconnect needs admin permission.") | |
| return BTResult(False, f"Bluetooth disconnect failed: {out[:160]}") | |