kable
                                
                                 kable copied to clipboard
                                
                                    kable copied to clipboard
                            
                            
                            
                        Combining different filter types for scanner not working
Using: com.juul.kable:core:0.28.0
When using a combination of scan filters such as Service and NamePrefix it only finds the devices matching the NamePrefix.
Examples:
Finds all devices advertising with service ID 1 and 2.
private val scanner = Scanner {
        filters = listOf(
            Filter.Service(SERVICE_ID_1),
            Filter.Service(SERVICE_ID_2),
        )
        scanSettings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .build()
    }
Finds only the devices with the name test and no devices advertising with the service ID 1 and 2.
private val scanner = Scanner {
        filters = listOf(
            Filter.Service(SERVICE_ID_1),
            Filter.Service(SERVICE_ID_2),
            Filter.NamePrefix("test"),
        )
        scanSettings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .build()
    }
I am not sure if I am doing something wrong but the documentation for scanning states that you can mix the different filter types but it is not working for me, any help is appreciated and please ping if there is any other information you would like me to provide.
Thanks for the report!
Can you provide Kable logs with at least Events log level?
We're currently not converting advertisements to peripherals during scanning but instead are using our local domain models. But I tried creating a peripheral when the flow returns the advertisements and added logging to it, but I am not receiving any logs and I am not really sure what I am looking for either? 😄
Any updates on this @twyatt?
Can you provide logs when performing your scan?
You can create a Scanner with logging via:
Scanner {
    logging {
        level = Events // or `Data`
    }
    filters = ..
}
Do you also see the issue when you don't use scanSettings?
Remove ScanSettings does not change anything in the results.
Adding the logging with Data level gives me these logs:
With all filters added (two Service filters and one NamePrefix):
Kable/Scanner I  Starting scan with 3 filter(s)
With just the two Service filters:
Kable/Scanner I  Starting scan with 2 filter(s)
With one Service and one NamePrefix:
Kable/Scanner I  Starting scan with 2 filter(s)
I looked through the code some more and found what I believe to be the issue.
When a service filter is present, Kable is filtering services out before other filters, when it should be inspecting attributes in one pass (when multiple filters are specified).
I'll try to find some time soonish to get in a fix. Thanks again for the issue report!
Cool, that would be a nice fix as we have to handle the scan filtering ourself at the moment and it's not ideal. Thanks for looking into it!
@jsundgren this has been slated (internally) for our next sprint. Work should begin in the coming weeks.
@jsundgren this has been slated (internally) for our next sprint. Work should begin in the coming weeks.
Sorry, this ended up being de-prioritized internally. I'll try to get it re-prioritized though.
@jsundgren can you try Kable 0.34.0 and let us know if this issue is resolved with the new scan filter DSL (#695)?
I have just tested 0.34.0 with 2xUUID + prefixed name as described in the READ.ME section. Unfortunately it seems not to work. (It did work with a single UUID + prefixed named, but that is not my usecase)
To have peripherals D1 and D3 emitted during a scan, you could use the following filters:
val scanner = Scanner {
    filters {
        match {
            services = listOf(uuidFrom("0000aa80-0000-1000-8000-00805f9b34fb")) // SensorTag
        }
        match {
            name = Filter.Name.Prefix("Ex")
        }
    }
}
@uruhans do you want to scan for devices that have both UUID 1 AND UUID 2, or are you wanting to search for devices that have UUID 1 OR UUID 2?
Some possible options (other variants also exist):
(UUID 1 and UUID 2) or Name.Prefix("Ex")
val scanner = Scanner {
    filters {
        match {
            services = listOf(uuidFrom("<uuid-1>"), uuidFrom("<uuid-2>"))
        }
        match {
            name = Filter.Name.Prefix("Ex")
        }
    }
}
(UUID 1 and Name.Prefix("Ex")) or (UUID 2 and Name.Prefix("Ex"))
val scanner = Scanner {
    filters {
        match {
            services = listOf(uuidFrom("<uuid-1>"))
            name = Filter.Name.Prefix("Ex")
        }
        match {
            services = listOf(uuidFrom("<uuid-2>"))
            name = Filter.Name.Prefix("Ex")
        }
    }
}
I want to scan for both UUID 1 OR UUID 2 OR for Prefix name. So if any of these criterias are true then I want them in my list.
I want to scan for both UUID 1 OR UUID 2 OR for Prefix name. So if any of these criterias are true then I want them in my list.
Have you tried something along the lines of?:
val scanner = Scanner {
    filters {
        match {
            services = listOf(uuidFrom("<uuid-1>"))
        }
        match {
            services = listOf(uuidFrom("<uuid-2>"))
        }
        match {
            name = Filter.Name.Prefix("Ex")
        }
    }
}
Thanks a lot for your help, that did the trick. Guess I was fooled by the listOf.
Thanks a lot for your help, that did the trick. Guess I was fooled by the listOf.
The way to think about it is:
- everything within a matchis AND'd (includinglistOfservices)
- each matchis OR'd
filters {
    match {
        filter1 AND filter2 .. AND filterN
    }
    OR
    match {
        filter1 AND filter2 .. AND filterN
    }
    OR
    ..
}