简体   繁体   English

有什么方法可以在不连接的情况下监控发现的BLE外设?

[英]Any way to monitor discovered BLE peripherals without connecting?

Is there any way of being notified if a discovered BLE peripheral moves out of range or otherwise drops out of sight? 如果发现的BLE外设超出范围或以其他方式失明,是否可以通过任何方式得到通知? I'm using rxBleClient.scanBleDevices() to build a list of devices in the area that are advertising, but before shipping this list to the main application I'd like to be sure that all the devices are still reachable. 我正在使用rxBleClient.scanBleDevices()在要发布的区域中构建设备列表,但是在将该列表发送到主应用程序之前,我想确保所有设备仍然可以访问。 What's the best way of doing this? 最好的方法是什么?

The vanilla Android Scan API allows for scanning BLE devices with callback types of: Vanilla Android Scan API允许使用以下回调类型扫描BLE设备:

/**
 * A result callback is only triggered for the first advertisement packet received that matches
 * the filter criteria.
 */
public static final int CALLBACK_TYPE_FIRST_MATCH = 2;

/**
 * Receive a callback when advertisements are no longer received from a device that has been
 * previously reported by a first match callback.
 */
public static final int CALLBACK_TYPE_MATCH_LOST = 4;

The same API is available via RxBleClient.scanBleDevices(ScanSettings, ScanFilter...) 可以通过RxBleClient.scanBleDevices(ScanSettings, ScanFilter...)使用相同的API

The CALLBACK_TYPE_FIRST_MATCH and CALLBACK_TYPE_MATCH_LOST are flags that can be put into ScanSettings . CALLBACK_TYPE_FIRST_MATCHCALLBACK_TYPE_MATCH_LOST是可以放入ScanSettings

The timeout after which the CALLBACK_TYPE_MATCH_LOST is triggered is somewhere around 10 seconds. 触发CALLBACK_TYPE_MATCH_LOST的超时时间约为10秒。 This may be an indication that a particular device is no longer in range/available. 这可能表明特定设备不在范围/可用范围内。

您可以创建一个Transformer ,该Transformer将收集扫描的设备并发出一个列表,该列表保持最新状态,具体取决于最近看到该设备的时间。

Robert, that may not be exactly what you expect but treat it as an example. 罗伯特,那可能不完全是您所期望的,但请以它为例。 My Transformer is emitting a list of items whenever it has been changed, either because an update from the scanner or the eviction happened (checked every second). 无论是因为扫描仪的更新还是驱逐发生(每秒检查一次),我的Transformer都会在更改项目时发出项目列表。

class RollingPairableDeviceReducer(
        private val systemTime: SystemTime,
        private val evictionTimeSeconds: Long,
        private val pairableDeviceFactory: PairableDeviceFactory
) : Observable.Transformer<ScannedDevice, List<PairableDevice>> {
    override fun call(source: Observable<ScannedDevice>): Observable<List<PairableDevice>> {
        val accumulator: MutableSet<PairableDevice> = Collections.synchronizedSet(mutableSetOf())
        return source
                .map { createPairableDevice(it) }
                .map { pairableDevice ->
                    val added = updateOrAddDevice(accumulator, pairableDevice)
                    val removed = removeOldDevices(accumulator)
                    added || removed
                }
                .mergeWith(checkEvictionEverySecond(accumulator))
                .filter { addedOrRemoved -> addedOrRemoved == true }
                .map { accumulator.toList() }
    }

    private fun createPairableDevice(scannedDevice: ScannedDevice)
            = pairableDeviceFactory.create(scannedDevice)

    private fun updateOrAddDevice(accumulator: MutableSet<PairableDevice>, emittedItem: PairableDevice): Boolean {
        val existingPairableDevice = accumulator.find { it.deviceIdentifier.hardwareId == emittedItem.deviceIdentifier.hardwareId }
        return if (existingPairableDevice != null) {
            accumulator.remove(existingPairableDevice)
            existingPairableDevice.updateWith(emittedItem)
            accumulator.add(existingPairableDevice)
            false
        } else {
            accumulator.add(emittedItem)
            true
        }
    }

    private fun checkEvictionEverySecond(collector: MutableSet<PairableDevice>): Observable<Boolean>
            = Observable.interval(1, TimeUnit.SECONDS)
            .map { removeOldDevices(collector) }

    private fun removeOldDevices(accumulator: MutableSet<PairableDevice>): Boolean {
        val currentTimeInMillis = systemTime.currentTimeInMillis()
        val evictionTimeMillis = TimeUnit.SECONDS.toMillis(evictionTimeSeconds)
        return accumulator.removeAll { (currentTimeInMillis - it.lastSeenTime) >= evictionTimeMillis }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM