Closed Boodums closed 1 year ago
Hi @Boodums
Interesting question, I haven't looked into getting services and characteristics ahead of connecting. My plugin does pass on the known services and characteristics when you connect to a device, but not ahead of time.
I'll look into it if it's possible and I'll get back to you soon.
I also saw that you added me on Discord, but I think I removed you by accident, you can send another request if you want a faster / direct response.
Thanks for the quick response! This capability was available on a Bluetooth interface that I used for an IOS app a few years ago but I don't know if Android supports it. I'm new to the Android platform. I sent another request through discord just in case, but I'll use GitHub for most correspondences. That way others who have the same question can benefit. Your Bluetooth interface seems pretty solid.
Hi @Boodums
It is possible to discover Services, but from what I'm seeing, Descriptors and Characteristics are only available if you have an existing connection. I made a branch called feature/scan-service-callback, which you can test out to see if it works for your case as well. The ExampleBleInteractor
and DeviceButton
in the Example/Scripts
show how it's used.
Thank you for adding this! I'll test it out later on today.
Thanks again for the time you put into this. I really do appreciate it. However this is not what I had in mind. I'm looking for a way to only add buttons to the BlePanel for which a specified Service exists in the BLE device. In practice, you could add a variable to the DeviceButton class (or ExampleBleInteractor class) called _preferredServiceUUID. If this variable is null then the program would behave just like it does now. If the variable contains the UUID of a Service then the java code would only pass back devices that have that service.
It seems that you could accomplish this by passing a ScanFilter object to the startScan function in your java code. You would use the ScanFilter.Builder.SetServiceData() function to populate the ScanFilter with the Service UUID. More information can be found at the link below. https://developer.android.com/guide/topics/connectivity/bluetooth/find-ble-devices
While I'd love to support such a wide range of functionalities from the Java environment into Unity, I'd rather keep it as generic as possible. Since all devices are passed, you can keep them in a list instead of having them instantly instantiated onto the panel and wait if the service you're looking for is passed along. From what I'm seeing there's two ways you could handle this:
private string _prefferedServiceUUID = "3698-0000-82c9-4adb-90cd-792b53207775";
public void ScanForDevices()
{
if (!_isScanning)
{
_isScanning = true;
BleManager.Instance.QueueCommand(new DiscoverDevices(OnDeviceFound, OnDeviceServiceFound, _scanTime * 1000));
}}
private void OnDeviceFound(string device, string name)
{
if (device != null)
{
}
}
private void OnDeviceServiceFound(string device, string service)
{
if (device != null && service != null && string.Equals(service, _prefferedServiceUUID))
{
DeviceButton button = Instantiate(_deviceButton, _deviceList).GetComponent<DeviceButton>();
button.Show(device, name);
}
}
DiscoverSpecificDevices
) and let it inherit from DiscoverDevices
, override the OnCommandReceived
and keep the same functionalities as the original, but have an extra check on if the service matches the one you're looking for (or passed along with the constructor) and only callback the devices that do.public class DiscoverSpecificDevices : DiscoverDevices
{
private string _preferredServiceUUID = string.Empty;
public DiscoverSpecificDevices(
Action<string, string> onDeviceDiscovered,
Action<string, string> onServiceDiscovered,
string filterService,
int discoverTime = StandardDiscoverTime) : base(onDeviceDiscovered, onServiceDiscovered, discoverTime)
{
_prefferedServiceUUID = filterService;
}
public override bool CommandReceived(BleObject obj)
{
switch (obj.Command)
{
case "DiscoveredDevice":
// Do nothing, since we're filtering
break;
case "DiscoveredDeviceService":
if(string.Equals(_prefferedServiceUUID, obj.Service)
{
OnDeviceDiscovered?.Invoke(obj.Device, obj.Name);
}
break;
}
return string.Equals(obj.Command, "FinishedDiscovering");
}
}
(all of the code above is written from memory, so they could contain syntax errors and should be considered as pseudo code)
It could be that I'm mis-understanding your question, but I believe either one of these solutions would with as the answer if I read things right. If I did misunderstand your question, then I will take a look at using the ScanFilter
instead with a class described in solution 2, so that users can filter out which values they do and do not want.
The first solution works well!
The only issue is that the name of the device is not available at the time the button is created. I can figure that part out.
Thank You!
Awesome, glad that this solution worked for you. I'll merge it with development
branch when I feel like it's ready.
Sounds great. Since you're going to merge it in to the main branch you may want to pass the device name to OnDeviceServiceFound so the button can be properly labeled.
Thanks again!
Sounds good, I'll add that later this week.
Have you had any problems with scanning devices? I have the timeout set to 30 seconds and sometimes it still cannot find my device?
The software lists all Bluetooth devices. Is there a way to have it only list devices that support a specific Gatt Service and/or Characteristic?