BluetoothGatt — এটি কী, পদ্ধতি এবং Android-এ GATT BLE প্রোটোকল

লেখক: IT Sectr প্রকাশিত: 2026-07-16 পড়ার সময়: 10 মিনিট

BluetoothGatt — একটি Android ক্লাস যা BLE সংযোগের উপর GATT (Generic Attribute Profile) ক্লায়েন্ট অপারেশনের জন্য API প্রদান করে। BluetoothGatt একটি দূরবর্তী GATT সার্ভারের (পেরিফেরাল BLE ডিভাইস) সাথে সংযোগ এনক্যাপসুলেট করে এবং সমস্ত প্রোফাইল অপারেশন পরিচালনা করে: সার্ভিস আবিষ্কার, বৈশিষ্ট্য পড়া এবং লেখা, বিজ্ঞপ্তি এবং ইঙ্গিত সাবস্ক্রাইব করা। BluetoothGatt-এর একটি ইনস্ট্যান্স BluetoothDevice.connectGatt() এর মাধ্যমে BluetoothGattCallback সহ পাওয়া যায়। Android Developers, 2026 অনুসারে, BluetoothGatt দ্বিমুখী BLE যোগাযোগের জন্য কেন্দ্রীয় ক্লাস, যা BLE 4.0 থেকে BLE 5.4 পর্যন্ত GATT অপারেশন সমর্থন করে।

মূল পয়েন্ট

  • BluetoothGatt — GATT ক্লায়েন্টের জন্য Android ক্লাস যা পেরিফেরাল ডিভাইসের সাথে BLE সংযোগ পরিচালনা করে
  • connectGatt() — BluetoothGatt তৈরি করার জন্য BluetoothDevice পদ্ধতি; এটি কনটেক্সট, autoConnect, callback এবং ট্রান্সপোর্ট গ্রহণ করে
  • discoverServices() — GATT হায়ারার্কি পাওয়ার পদ্ধতি: সার্ভিস (BluetoothGattService), বৈশিষ্ট্য (BluetoothGattCharacteristic)
  • readCharacteristic/writeCharacteristic — BluetoothGattCallback এর মাধ্যমে অ্যাসিনক্রোনাস ফলাফল সহ পড়া এবং লেখার পদ্ধতি
  • setCharacteristicNotification — বাধ্যতামূলক CCCD ডেস্ক্রিপ্টর লেখার সাথে BLE বিজ্ঞপ্তিতে সাবস্ক্রাইব করার পদ্ধতি

BluetoothGatt কী: সারাংশ এবং সংযোগ তৈরি

BluetoothGatt — একটি প্রক্সি অবজেক্ট যা Android ডিভাইস (কেন্দ্রীয়) এবং BLE পেরিফেরাল (সার্ভার) এর মধ্যে GATT সংযোগ উপস্থাপন করে। প্রতিটি BluetoothGatt ইনস্ট্যান্স একটি সক্রিয় BLE সংযোগের সাথে মিলে যায়। সমস্ত GATT প্রোফাইল অপারেশন এর মাধ্যমে সম্পাদিত হয়: আবিষ্কার, পড়া, লেখা, বিজ্ঞপ্তি। BluetoothGatt সরাসরি তৈরি হয় না — এটি BluetoothDevice.connectGatt() পদ্ধতি দ্বারা ফেরত দেওয়া হয়।

BluetoothGatt তৈরি করতে চারটি প্যারামিটার প্রয়োজন। Context — অ্যাপ্লিকেশন কনটেক্সট (Activity বা Application)। autoConnect — false হলে, Android অবিলম্বে সরাসরি সংযোগ শুরু করে; true হলে, Android ডিভাইস শনাক্ত হলে স্বয়ংক্রিয়ভাবে সংযোগ করে (ব্যাকগ্রাউন্ড সংযোগের জন্য উপযোগী)। BluetoothGattCallback — সমস্ত GATT ইভেন্টের জন্য বাধ্যতামূলক callback। transport — BluetoothDevice.TRANSPORT_LE (BLE) বা TRANSPORT_BREDR (Classic)। BLE ডিভাইসে সবসময় TRANSPORT_LE ব্যবহার করুন।

BluetoothGatt জীবনচক্র পাঁচটি অবস্থা নিয়ে গঠিত। DISCONNECTED — প্রাথমিক অবস্থা। CONNECTING — connectGatt কল করার পরে, নিশ্চিতকরণের আগে। CONNECTED — STATE_CONNECTED সহ onConnectionStateChange এর পরে। সংযোগের পরে GATT হায়ারার্কি পাওয়ার জন্য discoverServices() কল করা হয়। কাজ শেষ হওয়ার পরে — disconnect() এবং close() সিস্টেম রিসোর্স মুক্ত করার জন্য। close() কল না করলে, অ্যাপ্লিকেশন Android BLE সংযোগ সীমা (সাধারণত 4–8) শেষ করতে পারে।

kotlin
// BluetoothGatt সংযোগ তৈরি করা হচ্ছে
import android.bluetooth.*

class GattConnector(private val context: Context) {

    private var bluetoothGatt: BluetoothGatt? = null

    fun connect(device: BluetoothDevice): BluetoothGatt? {
        // পূর্ববর্তী সংযোগ থাকলে বন্ধ করুন
        close()

        bluetoothGatt = device.connectGatt(
            context,
            false,  // autoConnect = false ( )
            object : BluetoothGattCallback() {
                override fun onConnectionStateChange(
                    gatt: BluetoothGatt, status: Int, newState: Int
                ) {
                    when (newState) {
                        BluetoothProfile.STATE_CONNECTED -> {
                            // 2. সংযোগ স্থাপিত → আবিষ্কার
                            gatt.discoverServices()
                        }
                        BluetoothProfile.STATE_DISCONNECTED -> {
                            // 3. সংযোগ হারিয়ে গেছে
                            close()
                        }
                    }
                }

                override fun onServicesDiscovered(
                    gatt: BluetoothGatt, status: Int
                ) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        // 4. GATT হায়ারার্কি প্রাপ্ত
                        onGattReady(gatt)
                    }
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
        return bluetoothGatt
    }

    private fun onGattReady(gatt: BluetoothGatt) {
        // GATT পড়া/লেখা অপারেশনের জন্য প্রস্তুত
    }

    fun close() {
        bluetoothGatt?.disconnect()
        bluetoothGatt?.close()
        bluetoothGatt = null
    }
}

GattConnector ক্লাস সঠিক BluetoothGatt তৈরি প্রদর্শন করে। autoConnect=false প্যারামিটার মানে সরাসরি সংযোগ (স্ক্যান করা ডিভাইসের জন্য)। STATE_CONNECTED সহ onConnectionStateChange এ, অবিলম্বে discoverServices() কল করা হয়। onServicesDiscovered সংকেত দেয় যে GATT প্রস্তুত। close() ক্রমান্বয়ে disconnect() এবং close() কল করে — close() ছাড়া সিস্টেম রিসোর্স মুক্ত হয় না, যার ফলে BLE সংযোগ লিক হয়।

BluetoothGatt এর মাধ্যমে সার্ভিস এবং বৈশিষ্ট্য আবিষ্কার

discoverServices() — সংযোগের পরে কল করা প্রথম GATT পদ্ধতি। এটি BLE পেরিফেরালে সমস্ত সার্ভিসের অ্যাসিনক্রোনাস অনুসন্ধান শুরু করে। ফলাফল onServicesDiscovered() এ স্টেটাস কোড সহ আসে: GATT_SUCCESS (0) — সফল, 133 — GATT_ERROR, 8 — GATT_CONNECTION_TIMEOUT। সফল আবিষ্কারের পর, BluetoothGatt getServices() এর মাধ্যমে উপলব্ধ সার্ভিসের তালিকা পূরণ করে।

প্রতিটি BluetoothGattService এ BluetoothGattCharacteristic এর তালিকা থাকে। একটি বৈশিষ্ট্যের UUID, বৈশিষ্ট্য (PROPERTY_READ, PROPERTY_WRITE, PROPERTY_NOTIFY) এবং ঐচ্ছিক ডেস্ক্রিপ্টর থাকে। বৈশিষ্ট্যগুলি নির্ধারণ করে কোন অপারেশন অনুমোদিত: যদি কোনো বৈশিষ্ট্যের PROPERTY_READ না থাকে, readCharacteristic কল করলে ত্রুটি ফেরত আসবে। বৈশিষ্ট্য ডেস্ক্রিপ্টর পেতে getDescriptors() ব্যবহার করুন।

kotlin
// সার্ভিস আবিষ্কার এবং বৈশিষ্ট্য অনুসন্ধান
class GattServiceExplorer {

    // UUID দ্বারা সার্ভিস খুঁজুন
    fun findService(gatt: BluetoothGatt, uuid: UUID): BluetoothGattService? {
        return gatt.services?.firstOrNull { it.uuid == uuid }
    }

    // সার্ভিসে বৈশিষ্ট্য খুঁজুন
    fun findCharacteristic(
        service: BluetoothGattService,
        uuid: UUID
    ): BluetoothGattCharacteristic? {
        return service.characteristics?.firstOrNull { it.uuid == uuid }
    }

    // সমস্ত সমর্থিত বৈশিষ্ট্য অপারেশন পান
    fun getCharacteristicProperties(chars: BluetoothGattCharacteristic): List<String> {
        val props = mutableListOf<String>()
        with(chars.properties) {
            if (and(BluetoothGattCharacteristic.PROPERTY_READ) != 0) props.add("READ")
            if (and(BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) props.add("লিখুন")
            if (and(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) props.add("উত্তর_ছাড়া_লিখুন")
            if (and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) props.add("NOTIFY")
            if (and(BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) props.add("INDICATE")
        }
        return props
    }

    // সম্পূর্ণ GATT হায়ারার্কি লগ করুন
    fun dumpGattTree(gatt: BluetoothGatt) {
        gatt.services?.forEach { service ->
            print("Service: ${service.uuid}")
            service.characteristics?.forEach { char ->
                print("  Characteristic: ${char.uuid}, properties: ${char.properties}")
                char.descriptors?.forEach { desc ->
                    print("    Descriptor: ${desc.uuid}")
                }
            }
        }
    }
}

GattServiceExplorer ক্লাস GATT হায়ারার্কি নেভিগেট করার জন্য ইউটিলিটি প্রদান করে। findService এবং findCharacteristic UUID দ্বারা সার্ভিস এবং বৈশিষ্ট্য অনুসন্ধান করে। getCharacteristicProperties and() এর মাধ্যমে বৈশিষ্ট্যের বিট মাস্ক পরীক্ষা করে। dumpGattTree লগে সম্পূর্ণ হায়ারার্কি প্রিন্ট করে — BLE ডিভাইস ডিবাগ করার সময় উপযোগী। BluetoothGatt-এ সমস্ত অপারেশন সফল onServicesDiscovered এর পরেই করা উচিত, অন্যথায় getServices() খালি তালিকা ফেরত দেবে।

BLE বৈশিষ্ট্য পড়া: readCharacteristic এবং readDescriptor

readCharacteristic() — দূরবর্তী BLE ডিভাইস থেকে বৈশিষ্ট্যের মান পড়ার জন্য BluetoothGatt-এর অ্যাসিনক্রোনাস পদ্ধতি। ফলাফল BluetoothGattCallback-এর onCharacteristicRead() এ আসে। যদি কোনো ডিভাইসে 2+ ম্যাচিং বৈশিষ্ট্য থাকে (অসম্ভাব্য কিন্তু সম্ভব), readCharacteristic() অ-লক্ষ্যবস্তু পড়তে পারে — UUID এর পরিবর্তে BluetoothGattCharacteristic ইনস্ট্যান্সে readCharacteristic() কল করা বেশি নিরাপদ।

readDescriptor() — বৈশিষ্ট্য ডেস্ক্রিপ্টর মান পড়ার পদ্ধতি। একটি সাধারণ ডেস্ক্রিপ্টর হল CCCD (Client Characteristic Configuration Descriptor, UUID 0x2902), যা নির্ধারণ করে বিজ্ঞপ্তি সক্রিয় কিনা। ফলাফল onDescriptorRead() এ। অনুশীলনে ডেস্ক্রিপ্টর পড়া খুব কমই প্রয়োজন — CCCD setCharacteristicNotification() দ্বারা পরিচালিত হয়, কিন্তু কাস্টম ডেস্ক্রিপ্টরের (User Description 0x2901, Presentation Format 0x2904) জন্য readDescriptor() মেটাডেটা পাওয়ার একমাত্র উপায়।

MTU এবং বড় ডেটা পড়া — যদি বৈশিষ্ট্যের মান MTU (BLE 4.0-এর জন্য 23 বাইট) ছাড়িয়ে যায়, Android স্বয়ংক্রিয়ভাবে BLE স্ট্যাকের মাধ্যমে পড়ার অনুরোধের ক্রম দ্বারা ডেটা খণ্ডিত এবং পুনরায় একত্রিত করে। BLE 5.0+ এর জন্য বর্ধিত MTU (251 বাইট পর্যন্ত) সহ, খণ্ডনের প্রয়োজন নেই — একবার পড়ায় সম্পূর্ণ ডেটা ফেরত আসে। পড়ার আগে, আপনি সর্বোচ্চ MTU আলোচনার জন্য requestMtu() কল করতে পারেন।

kotlin
// BluetoothGatt এর মাধ্যমে বৈশিষ্ট্য এবং ডেস্ক্রিপ্টর পড়ুন
class GattReader {

    fun readHeartRate(gatt: BluetoothGatt) {
        // হার্ট রেট সার্ভিস UUID = 0x180D
        val service = gatt.getService(UUID.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
            ?: return
        // হার্ট রেট মেজারমেন্ট UUID = 0x2A37
        val characteristic = service.getCharacteristic(
            UUID.fromString("00002A37-0000-1000-8000-00805F9B34FB")
        ) ?: return

        if (hasProperty(characteristic, BluetoothGattCharacteristic.PROPERTY_READ)) {
            gatt.readCharacteristic(characteristic)
        }
    }

    fun readDescriptor(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        // CCCD (0x2902)
        val cccd = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        )
        cccd?.let { gatt.readDescriptor(it) }
    }

    // onCharacteristicRead callback-এ ডেটা প্রক্রিয়া করুন:
    fun parseHeartRate(value: ByteArray): Int {
        // BLE হার্ট রেট: bytes = flags, second = bpm
        return if (value.isNotEmpty()) value[1].toInt() and 0xFF else 0
    }

    private fun hasProperty(char: BluetoothGattCharacteristic, prop: Int): Boolean {
        return char.properties and prop != 0
    }
}

GattReader ক্লাস হার্ট রেট বৈশিষ্ট্য পড়া প্রদর্শন করে। সার্ভিস 0x180D-এ বৈশিষ্ট্য 0x2A37 (Heart Rate Measurement) রয়েছে — Bluetooth SIG-এর একটি মানক BLE প্রোফাইল। পড়ার আগে, hasProperty এর মাধ্যমে PROPERTY_READ বৈশিষ্ট্য পরীক্ষা করা হয়। parseHeartRate BLE হার্ট রেট ফরম্যাট পার্স করে: প্রথম বাইট — flags (ডেটা ফরম্যাট), দ্বিতীয় — bpm মান। CCCD ডেস্ক্রিপ্টর (0x2902) বিজ্ঞপ্তি অবস্থা পরীক্ষা করার জন্য পড়া হয়।

বৈশিষ্ট্য লেখা: WriteType সহ writeCharacteristic

writeCharacteristic() — BLE পেরিফেরালে ডেটা লেখার জন্য BluetoothGatt পদ্ধতি। Android API 33+ এ, writeCharacteristic() writeCharacteristic(request) দ্বারা প্রতিস্থাপিত হয়েছে, যেখানে BluetoothGattCharacteristicWriteRequest একটি অনুরোধ অবজেক্ট যা বৈশিষ্ট্য, বাইট অ্যারে এবং WriteType ধারণ করে। setValue() সহ পুরানো writeCharacteristic(characteristic) পদ্ধতি ডিপ্রিকেটেড। WriteType অনুরোধের আচরণ নির্ধারণ করে: WRITE_TYPE_DEFAULT (বৈশিষ্ট্যের বৈশিষ্ট্যের উপর নির্ভরশীল), WRITE_TYPE_NO_RESPONSE (প্রতিক্রিয়া ছাড়া) এবং WRITE_TYPE_SIGNED (অনুমোদন)।

WriteType নির্বাচন করা গতি এবং নির্ভরযোগ্যতাকে প্রভাবিত করে। WRITE_TYPE_DEFAULT সাধারণত withResponse (যদি বৈশিষ্ট্যের PROPERTY_WRITE থাকে) বা withoutResponse (যদি PROPERTY_WRITE_NO_RESPONSE থাকে) এর সাথে মিলে যায়। স্ট্রিমিং ডেটার (OTA আপডেট, লগ) জন্য WRITE_TYPE_NO_RESPONSE ব্যবহার করুন — সর্বোচ্চ থ্রুপুট। ডেলিভারি গ্যারান্টি সহ কমান্ডের (সক্রিয় করা, কনফিগার) জন্য — onCharacteristicWrite এর মাধ্যমে নিশ্চিতকরণ সহ WRITE_TYPE_DEFAULT।

kotlin
// Android API 33+ এ BLE বৈশিষ্ট্য লেখা
class GattWriter {

    // প্রতিক্রিয়া সহ লিখুন (withResponse)
    fun writeWithResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // API 33+: writeCharacteristic
            val request = BluetoothGattCharacteristicWriteRequest(
                characteristic,
                data,
                BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_DEFAULT,
                @android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            )
            gatt.writeCharacteristic(request)
        } else {
            // API < 33:   (deprecated)
            characteristic.setValue(data)
            gatt.writeCharacteristic(characteristic)
        }
    }

    // প্রতিক্রিয়া ছাড়া লিখুন (সর্বোচ্চ গতি)
    fun writeWithoutResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            val request = BluetoothGattCharacteristicWriteRequest(
                characteristic,
                data,
                BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_NO_RESPONSE,
                @android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            )
            gatt.writeCharacteristic(request)
        } else {
            characteristic.setValue(data)
            characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
            gatt.writeCharacteristic(characteristic)
        }
    }

    // onCharacteristicWrite callback (API 33+)
    private val writeCallback = object : BluetoothGattCallback() {
        override fun onCharacteristicWrite(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            value: ByteArray,
            status: Int,
            callbackType: Int
        ) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                print("Write success: ${value.size} bytes")
            }
        }
    }
}

GattWriter ক্লাস বিভিন্ন API স্তরের জন্য উভয় WriteTypes সমর্থন করে। writeWithResponse WRITE_TYPE_DEFAULT ব্যবহার করে — BLE ডিভাইস onCharacteristicWrite এর মাধ্যমে লেখা নিশ্চিত করে। writeWithoutResponse WRITE_TYPE_NO_RESPONSE ব্যবহার করে — ডেটা নিশ্চিতকরণ ছাড়া পাঠানো হয়, সর্বোচ্চ থ্রুপুট। API 33+ এ, BluetoothGattCharacteristicWriteRequest সহ নতুন writeCharacteristic(request) ব্যবহার করা হয়। API < 33 এ — পুরানো setValue() + writeCharacteristic().

বিজ্ঞপ্তিতে সাবস্ক্রাইব: setCharacteristicNotification এবং CCCD

setCharacteristicNotification() — পেরিফেরালে বৈশিষ্ট্য পরিবর্তন সম্পর্কে বিজ্ঞপ্তি সাবস্ক্রাইব করার জন্য BluetoothGatt পদ্ধতি। সাবস্ক্রিপশন সক্রিয় করার পর, BLE ডিভাইস onCharacteristicChanged() এর মাধ্যমে নতুন মান পাঠায়। তবে, setCharacteristicNotification() শুধুমাত্র স্থানীয় Android বিজ্ঞপ্তি সক্রিয় করে — BLE ডিভাইসে নিজেই বিজ্ঞপ্তি সক্ষম করতে, আপনাকে CCCD ডেস্ক্রিপ্টরে (0x2902) মান 0x0100 লিখতে হবে।

CCCD (Client Characteristic Configuration Descriptor) — একটি ডেস্ক্রিপ্টর যা BLE পেরিফেরাল থেকে বিজ্ঞপ্তি পাঠানো নিয়ন্ত্রণ করে। মান 0x0000 — বিজ্ঞপ্তি নিষ্ক্রিয়, 0x0100 — বিজ্ঞপ্তি সক্রিয়, 0x0200 — ইঙ্গিত সক্রিয়। CCCD তে লেখা setCharacteristicNotification() কল করার পর BluetoothGatt-এ writeDescriptor() এর মাধ্যমে করা হয়। Android স্বয়ংক্রিয়ভাবে CCCD লেখে না — এই দায়িত্ব ডেভেলপারের।

kotlin
// সঠিক BLE বিজ্ঞপ্তি সাবস্ক্রিপশন
class GattNotificationManager {

    // 1. বিজ্ঞপ্তি সক্ষম করুন
    fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        // ধাপ 1: স্থানীয় Android সাবস্ক্রিপশন
        val success = gatt.setCharacteristicNotification(characteristic, true)
        if (!success) {
            print("সাবস্ক্রাইব করতে ব্যর্থ")
            return
        }

        // ধাপ 2: BLE ডিভাইসে CCCD (0x2902) লিখুন
        val cccdDescriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        ) ?: return

        // 0x0100 = বিজ্ঞপ্তি, 0x0200 = ইঙ্গিত
        val cccdValue = if (characteristic.properties
            and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
            BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE  // [0x01, 0x00]
        } else {
            BluetoothGattDescriptor.ENABLE_INDICATION_VALUE     // [0x02, 0x00]
        }

        cccdDescriptor.setValue(cccdValue)
        gatt.writeDescriptor(cccdDescriptor)
    }

    // 2. বৈশিষ্ট্য আবিষ্কার
    fun disableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        gatt.setCharacteristicNotification(characteristic, false)
        val cccdDescriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        ) ?: return
        cccdDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)
        gatt.writeDescriptor(cccdDescriptor)
    }

    // 3. বিজ্ঞপ্তি callback
    private val notificationCallback = object : BluetoothGattCallback() {
        override fun onCharacteristicChanged(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            value: ByteArray,
            callbackType: Int
        ) {
            // BLE পেরিফেরাল থেকে নতুন মান
            print("Notification: ${value.size} bytes")
        }
    }
}

GattNotificationManager ক্লাস সঠিক দ্বি-পদক্ষেপ BLE বিজ্ঞপ্তি সাবস্ক্রিপশন প্রোটোকল বাস্তবায়ন করে। enableNotification প্রথমে Android-এ setCharacteristicNotification(true) কল করে, তারপর writeDescriptor এর মাধ্যমে CCCD ডেস্ক্রিপ্টরে 0x0100 লেখে। disableNotification বিপরীত অপারেশন করে। CCCD লেখা ছাড়া, BLE ডিভাইস বিজ্ঞপ্তি পাঠায় না — Android-এ BLE ডেভেলপারদের এটি সবচেয়ে সাধারণ ভুল।

BluetoothGattCallback সহ Kotlin-এ GATT ক্লায়েন্ট উদাহরণ

সম্পূর্ণ উদাহরণ Kotlin-এ GATT ক্লায়েন্টের যা অ্যাসিনক্রোনাস প্রক্রিয়াকরণের জন্য করুটিন ব্যবহার করে একক ম্যানেজারে BluetoothGatt তৈরি, আবিষ্কার, পড়া এবং বিজ্ঞপ্তি সাবস্ক্রিপশন একত্রিত করে।

kotlin
// Kotlin-এ করুটিন সহ সম্পূর্ণ GATT ক্লায়েন্ট
class GattClient(context: Context) {

    private val context = context.applicationContext
    private var gatt: BluetoothGatt? = null

    // করুটিন দিয়ে সংযোগ করুন
    suspend fun connect(device: BluetoothDevice): Boolean =
        suspendCoroutine { continuation ->
            gatt = device.connectGatt(
                context, false,
                object : BluetoothGattCallback() {
                    override fun onConnectionStateChange(
                        gatt: BluetoothGatt, status: Int, newState: Int
                    ) {
                        if (newState == BluetoothProfile.STATE_CONNECTED) {
                            gatt.discoverServices()
                        } else {
                            continuation.resume(false)
                        }
                    }

                    override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
                        continuation.resume(status == BluetoothGatt.GATT_SUCCESS)
                    }
                },
                BluetoothDevice.TRANSPORT_LE
            )
        }

    // করুটিনের মাধ্যমে বৈশিষ্ট্য পড়ুন
    suspend fun readCharacteristicValue(char: BluetoothGattCharacteristic): ByteArray? =
        suspendCoroutine { continuation ->
            gatt?.let { gatt ->
                // callback শনাক্তকরণের জন্য বৈশিষ্ট্য ট্যাগ সংরক্ষণ করুন
                gatt.setCharacteristic(char, null)  // API-এর জন্য < 33
                gatt.readCharacteristic(char)
            }
        }

    // সংযোগ বন্ধ করুন
    fun release() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

GATT ক্লায়েন্ট GattClient callback-ভিত্তিক BluetoothGatt API-কে অনুক্রমিক কলগুলিতে রূপান্তর করতে করুটিন (suspendCoroutine) ব্যবহার করে। connect() onServicesDiscovered-এর জন্য অপেক্ষা করে, যার পরে GATT হায়ারার্কি উপলব্ধ। readCharacteristicValue() onCharacteristicRead-এর জন্য অপেক্ষা করে। এই পদ্ধতি callback নেস্টিং দূর করে এবং BLE কোডকে রৈখিক করে তোলে। release() রিসোর্স ক্লিনআপ নিশ্চিত করে — Activity-র onDestroy বা ViewModel.onCleared-এ বাধ্যতামূলক কল।

সচরাচর জিজ্ঞাসিত প্রশ্ন

Android-এ BluetoothGatt কী?

BluetoothGatt — Android-এ GATT ক্লায়েন্টের জন্য ক্লাস যা পেরিফেরাল ডিভাইসের সাথে BLE সংযোগ পরিচালনা করে। এটি BluetoothDevice.connectGatt() এর মাধ্যমে তৈরি হয়, যা discoverServices(), readCharacteristic(), writeCharacteristic(), setCharacteristicNotification() পদ্ধতি প্রদান করে। সমস্ত অপারেশনের ফলাফল BluetoothGattCallback এর মাধ্যমে অ্যাসিনক্রোনাসভাবে আসে। BluetoothGatt ছাড়া, Android-এ দ্বিমুখী BLE যোগাযোগ অসম্ভব।

কেন onServicesDiscovered স্ট্যাটাস 133 ফেরত দেয়?

স্ট্যাটাস 133 (GATT_ERROR) Android BLE স্ট্যাকের অভ্যন্তরীণ ত্রুটি নির্দেশ করে। কারণ: আবিষ্কারের সময় ডিভাইস সংযোগ বিচ্ছিন্ন হয়েছে, MTU ন্যূনতম (23 বাইট) থেকে কম, বা BLE স্ট্যাক ওভারলোড। সমাধান: 500 ms বিলম্বে discoverServices() পুনরায় চেষ্টা করুন, ডিভাইস RSSI পরীক্ষা করুন এবং নিশ্চিত করুন যে পেরিফেরাল তার বর্তমান অবস্থায় GATT আবিষ্কার সমর্থন করে।

কীভাবে নিশ্চিতকরণ সহ বৈশিষ্ট্য লিখবেন?

নিশ্চিতকরণ সহ লেখার জন্য, WRITE_TYPE_DEFAULT (API 33+: BluetoothGattCharacteristicWriteRequest) সহ writeCharacteristic() কল করুন। সাফল্যের উপর, BLE ডিভাইস নিশ্চিতকরণ পাঠায় এবং Android GATT_SUCCESS সহ onCharacteristicWrite কল করে। যদি ডিভাইস 30 সেকেন্ডের মধ্যে (স্ট্যাক টাইমআউট) সাড়া না দেয়, callback ত্রুটি স্ট্যাটাস ফেরত দেয়। watchdog-এর জন্য postDelayed সহ Handler ব্যবহার করুন।

Android 33+ এ BLE নিয়ে কীভাবে কাজ করবেন?

Android 13+ (API 33) এ, BluetoothGatt পদ্ধতি পরিবর্তিত হয়েছে: writeCharacteristic() এখন BluetoothGattCharacteristicWriteRequest গ্রহণ করে, readCharacteristic() — BluetoothGattCharacteristicReadRequest। পুরানো setValue()/writeCharacteristic() ডিপ্রিকেটেড। BluetoothGattCallback-ও পরিবর্তিত হয়েছে: onCharacteristicRead(), onCharacteristicWrite(), onCharacteristicChanged() ByteArray value এবং callbackType গ্রহণ করে। শাখাকরণের জন্য Build.VERSION.SDK_INT ব্যবহার করুন।

Android কতগুলি BLE সংযোগ সমর্থন করে?

Android 4–8টি একসঙ্গে BLE GATT সংযোগ সমর্থন করে (প্রস্তুতকারক এবং Android সংস্করণের উপর নির্ভর করে)। Pixel/Google: 7 পর্যন্ত, Samsung: 5 পর্যন্ত, Xiaomi: 4 পর্যন্ত। সীমা অতিক্রম করলে, connectGatt null বা onConnectionStateChange ত্রুটি সহ ফেরত দেয়। বিপুল সংখ্যক ডিভাইসের সাথে কাজ করতে, চক্রীয় সংযোগ বা Bluetooth Mesh ব্যবহার করুন।

সারাংশ

  • BluetoothGatt — BLE সংযোগের জন্য Android GATT ক্লায়েন্ট, BluetoothDevice.connectGatt() এর মাধ্যমে BluetoothGattCallback সহ তৈরি
  • discoverServices() — BLE ডিভাইস সার্ভিস, বৈশিষ্ট্য এবং ডেস্ক্রিপ্টর পেতে সংযোগের পরে বাধ্যতামূলক পদক্ষেপ
  • পড়া — onCharacteristicRead() এ অ্যাসিনক্রোনাস ফলাফল সহ readCharacteristic(); বড় ডেটার জন্য MTU আলোচনা প্রয়োজন
  • লেখা — WriteType সহ writeCharacteristic(): DEFAULT (withResponse) বা NO_RESPONSE (নিশ্চিতকরণ ছাড়া)
  • বিজ্ঞপ্তি — দ্বি-পদক্ষেপ সক্রিয়করণ: setCharacteristicNotification() + মান 0x0100 সহ CCCD (0x2902) লেখা
  • API 33+ — অনুরোধ অবজেক্ট সহ নতুন পদ্ধতি writeCharacteristic(request) এবং readCharacteristic(request)
  • রিসোর্স মুক্ত করা — BLE সংযোগ লিক প্রতিরোধে disconnect() এবং close()-এর বাধ্যতামূলক কল

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন