kable icon indicating copy to clipboard operation
kable copied to clipboard

Combining different filter types for scanner not working

Open jsundgren opened this issue 1 year ago • 9 comments

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.

jsundgren avatar Feb 01 '24 13:02 jsundgren

Thanks for the report! Can you provide Kable logs with at least Events log level?

twyatt avatar Feb 01 '24 18:02 twyatt

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? 😄

jsundgren avatar Feb 02 '24 10:02 jsundgren

Any updates on this @twyatt?

jsundgren avatar Feb 08 '24 14:02 jsundgren

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?

twyatt avatar Feb 09 '24 18:02 twyatt

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)

jsundgren avatar Feb 12 '24 14:02 jsundgren

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!

twyatt avatar Feb 12 '24 17:02 twyatt

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 avatar Feb 13 '24 09:02 jsundgren

@jsundgren this has been slated (internally) for our next sprint. Work should begin in the coming weeks.

twyatt avatar Feb 21 '24 00:02 twyatt

@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.

twyatt avatar Jun 06 '24 07:06 twyatt

@jsundgren can you try Kable 0.34.0 and let us know if this issue is resolved with the new scan filter DSL (#695)?

twyatt avatar Jul 29 '24 23:07 twyatt

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 avatar Aug 13 '24 13:08 uruhans

@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")
        }
    }
}

twyatt avatar Aug 13 '24 17:08 twyatt

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.

uruhans avatar Aug 14 '24 08:08 uruhans

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")
        }
    }
}

twyatt avatar Aug 14 '24 17:08 twyatt

Thanks a lot for your help, that did the trick. Guess I was fooled by the listOf.

uruhans avatar Aug 15 '24 06:08 uruhans

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 match is AND'd (including listOf services)
  • each match is OR'd
filters {
    match {
        filter1 AND filter2 .. AND filterN
    }
    OR
    match {
        filter1 AND filter2 .. AND filterN
    }
    OR
    ..
}

twyatt avatar Aug 15 '24 07:08 twyatt