Скрипт подключения/отключения спаренного Bluetooth-устройства

Вопрос или проблема

Есть ли способ с помощью PowerShell или других инструментов подключать и отключать спаренное Bluetooth устройство? В основном, нажимать кнопку Подключить/Отключить в Bluetooth и других устройствах, но через командную строку любого вида (PowerShell, bat с использованием инструментов командной строки, код на C#, C++ и т.д.):

Bluetooth и другие устройства

Я нашел этот ответ, но он включает в себя отключение и повторное спаривание, что не сработает, потому что мои наушники должны быть в режиме спаривания, чтобы принять новое спаривание. Я бы предпочел не симулировать нажатия клавиш и щелчки мыши с помощью AutoIt или другого такого программного обеспечения.

Я написал код на C++ для этого, используя Win32 Bluetooth API’s BluetoothSetServiceState, но на самом деле достаточно использовать Bluetooth Command Line Tools.

Как оказалось, как только все службы, используемые устройством, отключены, устройство автоматически освобождается и disconnect’ится Windows. В моем случае это голос и музыка, согласно скриншоту, и большинство наушников будут работать так же.
Голос на самом деле представляет собой сервис Hands-Free (HFP), а музыка – это просто аудиопоток (A2DP). Идентификаторы услуг будут необходимы, и их можно определить с помощью команды btdiscovery из указанного пакета или через список Bluetooth-услуг. Голос HFP – это 111e, музыка A2DP – это 110b.

Согласно справке по команде btcom:

Использование:

btcom {-c|-r} {-bBluetoothAddress | -nFriendlyName} [-s{sp|dun|GUID|UUID}]

 -c  Создать ассоциацию между COM-портом и удаленной службой (Включить не-COM службу).
 -r  Удалить ассоциацию между COM-портом и удаленной службой (Отключить не-COM службу).
 -s  Удаленная служба для использования (по умолчанию - служба последовательного порта)
 -b  Bluetooth адрес удаленного устройства в формате (XX:XX:XX:XX:XX:XX). 
 -n  Дружественное имя удаленного устройства.

Чтобы отключить устройство, выполните следующее (работает только при запуске от имени администратора в моем случае, с использованием Windows 10 1809 (17763.437)):

"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "WH-1000XM3" -r -s111e
"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "WH-1000XM3" -r -s110b

Чтобы подключить снова, выполните то же самое с -c вместо -r. Это работает и для других устройств, не только для наушников, пока все службы/профили, к которым подключается Windows, отключены/включены.

Примечание: использование -n <дружественное имя> гораздо медленнее по сравнению с использованием -b <адрес> из-за выполнения обнаружения Bluetooth.

сочетания клавиш win 10 https://www.windowscentral.com/best-windows-10-keyboard-shortcuts

win-клавиша + K открывает боковое меню и тут же ищет Bluetooth-устройства.
затем щелкните по вашему уже спаренному устройству и подключите его.

Если решение от @MarcinJ с Bluetooth Command Line Tools для вас слишком медленное, особенно если вы хотите спарить устройство во время входящего звонка, попробуйте создать ярлык Windows:
(Кликните правой кнопкой мыши > Новый > Ярлык)

%windir%\explorer.exe ms-settings-connectabledevices:devicediscovery

Это отобразит панель отображения и аудио прямо на экране, которая на расстоянии одного клика от подключения.
И красивую иконку BT для ярлыка можно найти, например, в C:\Windows\System32\fsquirt.exe.

Возможно, Get-PnPDevice, Disable-PnPDevice и Enable-PnPDevice решат вашу задачу. Я не смог протестировать это, однако.

Пример:

$DeviceName = "YourDevice"
$BTDevice =  Get-PnpDevice | Where-Object {$_.FriendlyName -eq $DeviceName -and $_.class -eq "Bluetooth"} 

Disable-PnpDevice -InstanceId $BTDevice.DeviceID -Confirm:$false

Enable-PnpDevice -InstanceId $BTDevice.DeviceID -Confirm:$false

Измените переменную $DeviceName на имя вашего BT устройства.

Get-PnPDevice
Enable-PnPDevice
Disable-PnPDevice

Используя вдохновение из https://github.com/stanleyguevara/win10-bluetooth-headphones, я доработал этот скрипт, чтобы я мог подключать/отключать несколько устройств одним кликом ярлыка (или сочетанием клавиш, привязанным к ярлыку).

свойства ярлыка отключения

Мой форк здесь: https://github.com/nickboldt/win10-bluetooth-headphones

Скрипт AutoHotkey, предложенный Павлом, очень вдохновляющий, но компиляция требует AutoHotkey. Я перенес код на PowerShell, чтобы код не требовал AutoHotkey:

Param(
                [Parameter(Mandatory=$False,Position=1)]
                [string]$dnp
)

if($dnp -eq "/?") {
        Write-Host "использование: $($MyInvocation.InvocationName) [имя устройства]"
        exit
}

if(!$dnp) {
    $dnp="WH-1000XM4"
}

$devices = Get-ChildItem -Path HKLM:\SYSTEM\ControlSet001\Services\BTHPORT\Parameters\Devices
foreach($device in $devices) {
    $address=$device.pschildname.ToUpper()
    $name=$device.GetValue("Name")
    if($name -ne $null) {
        $printableName = ($name -notmatch 0 | ForEach{[char]$_}) -join ""
        if($printableName -eq $dnp) {
            $ma=$address
        }
    }
}

$gui="1"
if(!$ma) {
    Write-Host "Устройство $dnp не найдено.`r`nОстановка."
    if($gui -eq "1") {[System.Windows.Forms.MessageBox]::Show("Устройство $dnp не найдено.","Ошибка")}
    exit
}

Write-Verbose "Работа с устройством $dnp и адресом $ma."

$id=get-random
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct BLUETOOTH_DEVICE_INFO$id {
    public UInt32 dwSize;
    public UInt64 Address;
    public UInt64 ulClassofDevice;
    public bool fConnected;
    public bool fRemembered;
    public bool fAuthenticated;
    public decimal stLastSeen; //decimal такой же длинный, как SystemTime
    public decimal stLastUsed; //decimal такой же длинный, как SystemTime
    public string szName;
}

namespace bluco {
    public class Program$id {
        [DllImport("bthprops.cpl", CharSet = CharSet.Auto, SetLastError = true)]
        static extern uint BluetoothSetServiceState(IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO$id DeviceInfo, ref Guid guid, int ServiceFlags);

        public static void Main() {
            BLUETOOTH_DEVICE_INFO$id mdi = new BLUETOOTH_DEVICE_INFO$id {
                // ошибка 0x424, 1060 возникает, если нижеуказанный адрес неверен, это число, похоже, указывает на ERROR_SERVICE_DOES_NOT_EXIST
                Address = Convert.ToUInt64("$ma", 16),
                szName = "WH-1000XM5",
                // 72 - это размер BLUETOOTH_DEVICE_INFO$id без строки szName
                // согласно спецификации, строка szName имеет максимум 248 wchars
                dwSize = (uint) (72 + 4*248)
            };

            Guid mUUID = new Guid("0000111e-0000-1000-8000-00805f9b34fb"); // https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
            uint hr0 = BluetoothSetServiceState(IntPtr.Zero, ref mdi, ref mUUID, 1);
            mUUID = new Guid("0000110b-0000-1000-8000-00805f9b34fb"); // https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
            uint hr1 = BluetoothSetServiceState(IntPtr.Zero, ref mdi, ref mUUID, 1);
            if(hr0 == 0 && hr1 == 0) {
                Console.WriteLine("Bluetooth подключен.");
                #pragma warning disable 162
                if("$gui"=="1") System.Windows.Forms.MessageBox.Show("Bluetooth подключен.","Подключить");
                #pragma warning restore 162
            }
            if(hr0 != 0 || hr1 != 0) {
                mUUID = new Guid("0000111e-0000-1000-8000-00805f9b34fb");
                hr0 = BluetoothSetServiceState(IntPtr.Zero, ref mdi, ref mUUID, 0);
                // ошибка 0x424, 1060 возникает, если нижеуказанный адрес неверен, это число, похоже, указывает на ERROR_SERVICE_DOES_NOT_EXIST
                mUUID = new Guid("0000110b-0000-1000-8000-00805f9b34fb");
                hr1 = BluetoothSetServiceState(IntPtr.Zero, ref mdi, ref mUUID, 0);
                if(hr0 == 0 && hr1 == 0) {
                    Console.WriteLine("Bluetooth отключен.");
                    #pragma warning disable 162
                    if("$gui"=="1") System.Windows.Forms.MessageBox.Show("Bluetooth отключен.","Отключить");
                    #pragma warning restore 162
                }
            }
        }
    }
}
"@ -Language CSharp -ReferencedAssemblies System.Windows.Forms

iex "[bluco.Program$id]::Main()"

Теперь я могу включать и выключать свои Bluetooth наушники из командной строки, используя PowerShell.

https://github.com/m2jean/ToothTray – это проект, реализующий подключение/отключение с Bluetooth аудио устройствами. Из его README.md:

Вместо использования API Bluetooth Windows, нужно использовать Windows Core Audio API для подключения Bluetooth аудио. В конечном итоге это драйвер подключает Bluetooth устройство к аудиосистеме Windows, и нам нужно получить интерфейс к Bluetooth аудио драйверу.

После того, как Bluetooth аудио устройства будут спарены и драйвера установлены, они появятся в Windows как аудио точки, которые можно перечислить с помощью EnumAudioEndpoints. Каждая точка имеет различные свойства. Их доступность зависит от типа точки. Мы можем перечислить свойства программно или просмотреть их на вкладке “Сведения” устройства в Диспетчере устройств.

Одно полезное свойство – это state точки, которое говорит нам, подключено ли Bluetooth аудио устройство. Если оно подключено, состояние будет DEVICE_STATE_ACTIVE. В противном случае оно будет DEVICE_STATE_UNPLUGGED.

После получения точек мы должны использовать API топологии устройств, чтобы получить интерфейс к драйверу. В модели драйвера Windows (WDM) драйвера выставляют оборудование и свою функциональность с помощью графа компонентов ядрового стриминга (KS). Путем навигации через топологию мы можем найти компоненты KS, которые фактически контролируют подключение Bluetooth аудио устройства.

И оказывается, что компонент KS, который мы ищем, всегда является фильтром KS, непосредственно подключенным к аудиоточке (что могло быть указано в соответствующих документах по разработке драйвера WDM). Мы можем получить фильтр, получив соединитель фильтра от соединителя точки. Затем мы можем использовать интерфейс IKsControl фильтра, чтобы отправить запрос свойства KSPROPSETID_BtAudio драйверу, который аналогичен запросам IO. Отправляя либо KSPROPERTY_ONESHOT_RECONNECT, либо KSPROPERTY_ONESHOT_DISCONNECT, мы просим драйвер подключиться или отключиться от Bluetooth аудио устройства.

Подробная реализация доступна в его коде.

Я форкнул его и сделал его основные функции в CLI-версии для использования в сценариях: https://github.com/shunf4/ToothTrayCli

Обратите внимание, что вышеуказанное относится только к Bluetooth аудио устройствам.

Отредактировано на основе ответа OP.

Смотрим на подлежащий класс, этот элемент не доступен для программного доступа.

Bluetooth​Device.​Close Метод

Когда будет реализовано Close/Disconnect?
[Windows.Devices.Bluetooth.BluetoothDevice]

Когда будет реализовано Close/Disconnect? Планируете ли вы иметь отключение? Dispose() не закрывает соединение

849 открыто 9 января 2019 года

Не похоже, что существует другой API документ, который говорит обратное. Так что, похоже, вы застряли с SendKeys, AutoIT и т.д., по крайней мере, на данный момент.

Довольно старый пост, но я недавно нашел способ сделать это без дополнительных сторонних инструментов.

Кратко:
В Windows 11 перейдите в Настройки > Система > Для разработчиков и включите Режим разработчика, Портал устройства и Ограничить только для циклических подключений. Отключите Аутентификацию. Перейдите на http://localhost:50080/#Bluetooth, чтобы найти ID вашего уже спаренного Bluetooth устройства; преобразуйте его в base64. Затем следующая команда будет работать из командной строки:
curl -d "" http://localhost:50080/api/bt/connectdevice?deviceId={ID_in_base64}

Длинная версия:
Это решение использует возможности Портала устройства Windows, который позволяет вам администрировать свой ПК через веб-запросы. Узнайте больше о том, что он может делать здесь. Перейдите в Настройки > Система > Для разработчиков и включите Режим разработчика, затем включите Портал устройства. Это вызовет установку Пакета режима разработчика, что может занять несколько минут и может потребовать перезагрузки. Как только он будет включен, включите Ограничить только для циклических подключений. Это очень важно по соображениям безопасности; это означает, что вы сможете получить доступ к Порталу устройства только с вашего локального ПК. В противном случае любой, кто в той же сети, сможет прочитать все файлы на вашем ПК. Как только вы это сделаете, вы можете безопасно отключить Аутентификацию. В качестве альтернативы, вы можете оставить Аутентификацию включенной, но имейте в виду, что вам придется указать имя пользователя и пароль в открытом виде в ваших веб-запросах позже.

Как только это сделано, вы увидите URL для Портала устройства, который должен выглядеть как http://localhost:50080, хотя номер порта может быть другим. Перейдите по этому URL, и вы увидите Портал устройства; выберите Bluetooth в боковом меню, чтобы увидеть ваши Bluetooth устройства. Предполагая, что ваше Bluetooth устройство уже спарено, вы увидите его в списке, даже если оно в данный момент отключено. Скопируйте полный ID вашего Bluetooth устройства и преобразуйте его в base64 с помощью сайта, такого как https://base64.guru/converter.

Наконец, вы можете использовать REST API, чтобы подключить или отключить ваше Bluetooth устройство. Самый простой способ – использовать curl, который по умолчанию установлен в Windows в наши дни. Но вы также можете использовать пакет requests в Python, если хотите сделать что-то еще более изысканное. URL-адреса для подключения или отключения вашего устройства следующие:

http://localhost:50080/api/bt/connectdevice?deviceId={ID_in_base64}
http://localhost:50080/api/bt/disconnectdevice?deviceId={ID_in_base64}

Чтобы использовать curl, включите флаг -d с пустыми кавычками (что устанавливает Длину содержимого равной 0), затем URL, вот так: curl -d "" {url}

Я успешно протестировал следующий vbs-скрипт в Windows 10. Здесь я симулирую нажатия клавиш, используя команду SendKeys. Количество {TAB} будет отличаться на вашей системе, чтобы достичь имени Bluetooth устройства.

Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "ms-settings:bluetooth"
WScript.Sleep 2500 
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{ENTER}"
WScript.Sleep 500 ' 
WshShell.SendKeys "{TAB}"
WScript.Sleep 500 ' 
WshShell.SendKeys "{ENTER}"

Ответ или решение

Чтобы подключить или отключить сопряжённое Bluetooth-устройство с помощью скриптов, можно использовать несколько подходов. Этот процесс может быть реализован с помощью PowerShell, C#, и других инструментов. Ниже приводится подробное описание нескольких методов:

1. Использование Bluetooth Command Line Tools

Существует набор инструментов командной строки для работы с Bluetooth на Windows, известный как Bluetooth Command Line Tools. Он позволяет подключать и отключать Bluetooth-устройства, не требуется повторное сопряжение.

Команды для отключения устройства:

"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "Ваше_Устройство" -r -s111e
"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "Ваше_Устройство" -r -s110b

Эти команды отключают сервисы HFP (Voice) и A2DP (Music) для устройства. Не забудьте заменить "Ваше_Устройство" на ваше реальное имя устройства.

Команды для подключения устройства:

"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "Ваше_Устройство" -c -s111e
"C:\Program Files (x86)\Bluetooth Command Line Tools\bin\btcom" -n "Ваше_Устройство" -c -s110b

2. Использование PowerShell

Другой подход — использование PowerShell для управления Bluetooth-устройствами:

$DeviceName = "Ваше_Устройство"
$BTDevice = Get-PnpDevice | Where-Object {$_.FriendlyName -eq $DeviceName -and $_.class -eq "Bluetooth"} 

Disable-PnpDevice -InstanceId $BTDevice.DeviceID -Confirm:$false
Enable-PnpDevice -InstanceId $BTDevice.DeviceID -Confirm:$false

Этот скрипт сначала отключает, а затем включает устройство. Параметр $DeviceName следует заменить на имя вашего устройства.

3. Использование C

Можно использовать Win32 Bluetooth API для управления Bluetooth-устройствами. Например:

using System;
using System.Runtime.InteropServices;

public class BluetoothManager
{
    [DllImport("bthprops.cpl", SetLastError = true)]
    public static extern uint BluetoothSetServiceState(IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO deviceInfo, ref Guid guid, int serviceFlags);

    public static void ToggleBluetoothDevice(string address, bool connect)
    {
        Guid serviceUUID = connect ? new Guid("0000111e-0000-1000-8000-00805f9b34fb") : new Guid("0000110b-0000-1000-8000-00805f9b34fb");
        BLUETOOTH_DEVICE_INFO deviceInfo = new BLUETOOTH_DEVICE_INFO { Address = Convert.ToUInt64(address, 16) };

        uint result = BluetoothSetServiceState(IntPtr.Zero, ref deviceInfo, ref serviceUUID, connect ? 1 : 0);
        if (result == 0) 
        {
            Console.WriteLine(connect ? "Устройство подключено." : "Устройство отключено.");
        }
    }
}

Замените address на фактический адрес Bluetooth-устройства.

4. Использование Device Portal на Windows 11

Если у вас Windows 11, вы можете включить Device Portal для управления Bluetooth-устройствами через HTTP-запросы.
После включения Device Portal вы можете использовать curl для подключения или отключения:

curl -d "" http://localhost:50080/api/bt/connectdevice?deviceId={ID_в_base64}

Для отключения:

curl -d "" http://localhost:50080/api/bt/disconnectdevice?deviceId={ID_в_base64}

Заключение

Все описанные методы имеют свои особенности и могут быть выбраны в зависимости от ситуации. Использование командной строки и PowerShell обеспечивает высокую гибкость и может быть внедрено в автоматизированные скрипты и процессы. Если же вы предпочитаете программный подход, тогда C# сценарий будет более подходящим.

Оцените материал
Добавить комментарий

Капча загружается...