I like to read the battery status of connected bluetooth headsets. Using a script I want to be able to print it on my Win10 desktop with something like Rainmeter.
I'm using WinRT namespaces to successfully find and connect to my Bluetooth headsets, but to open a stream and read the contents (e.g. battery status) I have to deal with an Interface.
What I got working so far:
#Add Type WinRT so that we can make use of Universal Windows Platform (UWP)
Add-Type -AssemblyName System.Runtime.WindowsRuntime
#To deal with asynchronous functions/actions in WinRT we can use the following functions: Await and AwaitAction
#With thanks to Ben N. on https://superuser.com/questions/1341997/using-a-uwp-api-namespace-in-powershell
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
Function AwaitAction($WinRtAction) {
$asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
$netTask = $asTask.Invoke($null, @($WinRtAction))
$netTask.Wait(-1) | Out-Null
}
#Get the relevant DeviceId from $btDeviceAll(not shown here for brevity)
$SonyWH1000XM3id = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:##'
#Get relevant btDevice by referencing the DeviceId.
$btDeviceClass = [Windows.Devices.Bluetooth.BluetoothDevice,Windows.Devices.Bluetooth,ContentType = WindowsRuntime]
$btDevice = Await ($btDeviceClass::FromIdAsync($SonyWH1000XM3id)) ([Windows.Devices.Bluetooth.BluetoothDevice])
#Choose the relevant $btRfcommServices.services[] from $btRfcommServices(not shown here for brevity, my sony headset has HFP handsfree policy available)
$btHFPServiceUUID = '0000111e-0000-1000-8000-00805f9b34fb'
$btHFPConnectionHostName = '##:##:##:##:##:##'
$btHFPConnectionServiceName = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:###RFCOMM:00000000:{00001108-0000-1000-8000-00805f9b34fb}'
#Connect to the device with a StreamSocket
[Windows.Networking.HostName,Windows.Networking,ContentType = WindowsRuntime]
[Windows.Networking.Sockets.StreamSocket,Windows.Networking.Sockets,ContentType = WindowsRuntime]
$btHostName = [Windows.Networking.HostName]($btHFPConnectionHostName)
$btSocket = New-Object Windows.Networking.Sockets.StreamSocket
AwaitAction ($btSocket.ConnectAsync($btHostName,$btHFPConnectionServiceName))
Now, to get actual data I need to use the $btSocket.InputStream Property via:
- the method:
IInputStream.ReadAsync(IBuffer, UInt32, InputStreamOptions); or - the class
DataReader(IInputStream).
Unfortunately, .InputStream is an interface IInputStream but Powershell sees an System.__ComObject and I have no idea how to tell Powershell what it is. Therefore, the second method with DataReader(IInputStream) produces an error. The first method, by Invoking ReadAsync gives me Object of type 'System.__ComObject' cannot be converted to type 'Windows.Foundation.IAsyncAction' when:
$InputStreamOptionPartial = [Windows.Storage.Streams.InputStreamOptions]::Partial
$btByte = New-Object Byte[] 1024
$btIBuffer = [System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions]::AsBuffer($btByte)
$bfSize = [UInt32]"1024"
$btReadAsync = [Windows.Storage.Streams.IInputStream].GetMethod('ReadAsync',[type[]]@('Windows.Storage.Streams.Buffer','UInt32','Windows.Storage.Streams.InputStreamOptions'))
AwaitAction ($btReadAsync.Invoke($btSocket.InputStream,@($btIBuffer,$bfSize,$InputStreamOptionPartial)))
BTW: I've also tried performing it al in C# script in Powershell, but I can't even get C# script to use WinRT namespaces, only using system.io etc.
Can someone explain to me (or type out) how to get DataReader() to accept the StreamSocket.IInputStream or get a working Buffer from ReadAsync?? Alternative scripting solutions are also welcome. Thank you.