Android में BLE डिवाइस नाम परिवर्तन का पता लगाना

Dec 01 2020

हमारे पास एक BLE डिवाइस है जो हम उस डिवाइस के नाम के माध्यम से डेटा आउटपुट पर काम कर रहे हैं। डिवाइस ठीक से काम कर रहा है और nRF कनेक्ट जैसे ऐप का उपयोग करके नामों को ठीक से बदलते देखा जा सकता है। हालाँकि, हम अपने ही एंड्रॉइड ऐप में ऐसा करने में मुश्किल समय बिता रहे हैं। हम उपकरणों का ठीक पता लगा सकते हैं, लेकिन वे लगभग उन मूल नामों से आगे नहीं बढ़ेंगे, जो उन्हें दिए गए थे।

मेरे द्वारा शुरू किए गए कोड में एक लूप है जिसे onResume () में शुरू किया गया है जो एक BluetoothLeScanner और startScan () फ़ंक्शन का उपयोग करके स्कैन करता है।

public void BLEScan(final boolean enable){

    final int SCAN_PERIOD = 12000;
    final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

    if (enable) {
        Log.d(TAG, "Starting Scan");
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                BLEScan(false);
                invalidateOptionsMenu();
            }
        }, SCAN_PERIOD);
        
        bluetoothLeScanner.flushPendingScanResults(mLeScanCallback);
        bluetoothLeScanner.startScan(mLeScanCallback);
    } else {
        Log.d(TAG, "Stopping Scan");
        bluetoothLeScanner.flushPendingScanResults(mLeScanCallback);
        bluetoothLeScanner.stopScan(mLeScanCallback);
        
        mHandler.removeCallbacksAndMessages(null);

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                BLEScan(true);
            }
        }, SCAN_PERIOD);
    }
}

और यह mLeScanCallback में पाया जाता है कि उपकरणों के आधार पर फ़िल्टर करता है। मूल रूप से, अगर यह पहले एक उपकरण नहीं देखा है, यह इसे बीकन की सूची में जोड़ता है। लेकिन, अगर इसे पहले देखा है, तो यह बीकन के देखा () फ़ंक्शन के साथ बीकन के नाम के साथ मानों को अपडेट करता है जैसा कि देखा जाएगा कि जानकारी कहां से आएगी। दोनों मामलों में, यह नई जानकारी को पॉप्युलेट करने के लिए अपने एडेप्टर को अपडेट करेगा।

private ScanCallback mLeScanCallback =
    new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            final ScanResult res2 = result;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    BluetoothDevice device = res2.getDevice();
                    String address = device.getAddress();
                    
                    if (device.getName() != null){
                        if (device.getName().contains("ABT:")){
                            if (!mLeBeacons.containsKey(address)){
                                BleBeacon beacon = new BleBeacon(device.getName(), address);
                                bleList.add(beacon);
                                adapter.notifyDataSetChanged();

                                mLeBeacons.put(device.getAddress(), beacon);
                            } else {
                                for (int x = 0; x < bleList.size(); x++){
                                    if (device.getAddress().equals(bleList.get(x).getMAC())){
                                        bleList.get(x).seen(device.getName());
                                        adapter.notifyDataSetChanged();
                                    }
                                }
                            }
                        }
                    }
                }
            });
        }
    };

हालांकि, नाम अपडेट करने के बाद भी mLeScanCallback केवल मूल नाम ही लौटाएगा।

यहाँ से कुछ खोज करने के बाद, मैं जो खोज करता रहा, वह फ़ंक्शन fetchUuidsWithSdp () का उपयोग करना था और इस तरह के नाम परिवर्तन को देखने के लिए ACTION_FOUND, ACTION_UUID, ACTION_DISCOVERY -FINISHED, और ACTION_NAME_CHANGED जैसे इरादे। इसलिए, मैंने mLeScanCallback में fetchUuidsWithSdp () जोड़ा। हालाँकि, जब यह Intents को ट्रिगर करेगा, तब भी नाम अपडेट नहीं हो रहा था। मैंने वास्तविक इंटेंट्स में fetchUuidsWithSdp () कॉल करने की कोशिश की, लेकिन इससे भी मदद नहीं मिली। यदि मैं अपने फोन की स्क्रीन को बंद कर देता हूं या BLE डिवाइस से काफी दूर चला जाता है, तो पर्याप्त रूप से ACTION_NAME_CHANGED कभी-कभी आग लगा देगा। लेकिन, सभी ऑनपॉज़ () करता है कॉल super.onPause()और BLEScan(false)। और, चूंकि ये चीजें थीं जो मैं पहले से ही अपने पाश में कर रहा था, मुझे यकीन नहीं था कि यह मेरे कोड में कैसे लाया जाए जबकि यह जाग रहा था।

अधिक खोज के बाद, मैंने पाया कि, fetchUuidsWithSdq () फ़ंक्शन का उपयोग करने के लिए, आपको अपने ब्लूटूथ एडेप्टर के startDiscovery () फ़ंक्शन का उपयोग करने की आवश्यकता है। इसलिए, मैंने इसका उपयोग करने के लिए BLEScan को बदल दिया, पूरी तरह से mLeScanCallback को काट दिया।

public void BLEScan(final boolean enable){
    final int SCAN_PERIOD = 12000;
    if (enable) {
        Log.d(TAG, "Starting Scan");
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                BLEScan(false);
                invalidateOptionsMenu();
            }
        }, SCAN_PERIOD);

        if (mBluetoothAdapter.isDiscovering()){
            mBluetoothAdapter.cancelDiscovery();
        }
        mBluetoothAdapter.startDiscovery();
    } else {
        Log.d(TAG, "Stopping Scan");
        mBluetoothAdapter.cancelDiscovery();

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                BLEScan(true);
            }
        }, SCAN_PERIOD);
    }
}

हालाँकि, जब इंटेंट्स पहले फायरिंग कर रहे थे, तब वे अभी नहीं थे, भले ही वे मेरे इरादे फ़िल्टर में थे। कुछ और खोज करने के बाद, मैंने कुछ लोगों को यह कहते हुए पाया कि StartDiscovery () Le डिवाइस के साथ काम नहीं करता है। इसलिए, मैंने खोज किया कि आप इसके बजाय क्या उपयोग करने वाले हैं ... जिसने मुझे ब्लूटूथलेनर के साथ शुरुआत करने के लिए वापस लाया। उस समय, मुझे एहसास हुआ कि मैं एक मंडली में गया हूँ और मदद की ज़रूरत है।

मैं अपनी पूरी प्रक्रिया पर चला गया क्योंकि, लाइनों के साथ, मैं कुछ याद किया। मैं अभी नहीं जानता कि यह कहाँ था। क्या मुझे startScan () का उपयोग करना चाहिए? क्या मैं स्टार्टडिस्कवरी () का उपयोग ठीक से नहीं कर रहा हूँ? या कुछ और है जो मुझे पूरी तरह से उपयोग करना चाहिए? तथ्य यह है कि ACTION_NAME_CHANGED को कभी-कभी निकाल दिया जाता है, जिससे मैं उस पर वापस जाना चाहता हूं, लेकिन डिवाइस जागृत होने पर मैं इसे हर समय कैसे काम कर सकता हूं?

जवाब

M.Kotzjan Dec 02 2020 at 21:16

मुझे लगता है कि आपको बस एंड्रॉइड पर कैशिंग की समस्या हो सकती है। संभावित समाधान के लिए यह उत्तर यहां देखें:https://stackoverflow.com/a/50745997/7473793

Seth Dec 03 2020 at 23:48

हालांकि मुझे नहीं पता था कि मैं अपने मूल कोड में क्या गलत कर रहा था (हालांकि यह लगता है कि एंड्रॉइड इस संबंध में बस टूट सकता है), मुझे एक वर्कअराउंड मिला। nRF के NFC टूलबॉक्स में यह स्रोत कोड उपलब्ध है और अतिरिक्त फिल्टर के साथ बैचों में स्कैन करता है और साथ ही यह नॉर्ड लाइब्रेरी से अपना ले स्कैनर है। यहाँ मेरा स्कैन फंक्शन कैसा दिखता है:

    public void BLEScan(final boolean enable){

        final BluetoothLeScannerCompat bluetoothLeScanner = BluetoothLeScannerCompat.getScanner();
        final ScanSettings settings = new ScanSettings.Builder()
                .setLegacy(false)
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(1000).setUseHardwareBatchingIfSupported(false).build();
        final List<ScanFilter> filters = new ArrayList<>();
        ParcelUuid Uuid = new ParcelUuid(UUID.fromString(uuidString));
        filters.add(new ScanFilter.Builder().setServiceUuid(Uuid).build());

        if (enable) {
            Log.d(TAG, "Starting Scan");
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    BLEScan(false);
                    invalidateOptionsMenu();
                }
            }, SCAN_PERIOD);

            bluetoothLeScanner.startScan(filters, settings, mLeScanCallback);
        } else {
            BLEService.refreshGatt();
            Log.d(TAG, "Stopping Scan");
            bluetoothLeScanner.stopScan(mLeScanCallback);

            mHandler.removeCallbacksAndMessages(null);

            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    BLEScan(true);
                }
            }, SCAN_PERIOD);
        }
    }

और मेरा कॉलबैक इस तरह दिखता है:

    private no.nordicsemi.android.support.v18.scanner.ScanCallback mLeScanCallback =
            new no.nordicsemi.android.support.v18.scanner.ScanCallback() {
                @Override
                public void onBatchScanResults(@NonNull final List<no.nordicsemi.android.support.v18.scanner.ScanResult> results) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            for (final no.nordicsemi.android.support.v18.scanner.ScanResult result : results){
                                BluetoothDevice device = result.getDevice();

                                if (device != null){
                                    String address = device.getAddress();
                                    String name = result.getScanRecord() != null ? result.getScanRecord().getDeviceName() : null;

                                    if (!mLeBeacons.containsKey(address)) {
                                        BleBeacon beacon = new BleBeacon(device.getName(), address);
                                        bleList.add(beacon);
                                        adapter.notifyDataSetChanged();

                                        mLeBeacons.put(device.getAddress(), beacon);
                                    } else {
                                        for (int x = 0; x < bleList.size(); x++){
                                            if (device.getAddress().equals(bleList.get(x).getMAC())){
                                                bleList.get(x).seen(device.getName());
                                                adapter.notifyDataSetChanged();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    });
                }

वह चाल के समान लग रहा था। हालाँकि आपको अपनी निर्भरता में निम्नलिखित को जोड़ना होगा।

implementation 'no.nordicsemi.android.support.v18:scanner:1.4.2'

उसके बाद, मेरा नाम ACTION_NAME_CHANGE इरादा ठीक से चालू हो रहा है और डेटा अपडेट हो रहा है।

मुझे यकीन नहीं है कि यह परिणाम से नाम प्राप्त करने का अलग तरीका है या यदि यह बैच स्कैनिंग है। लेकिन, अगर नॉर्डिक भी मानक एंड्रॉइड BLE लाइब्रेरी का उपयोग नहीं कर रहा है, तो मुझे लगता है कि यह जाने का सबसे अच्छा तरीका है।