1 Traditional Bluetooth and Low power Bluetooth

Traditional Bluetooth is also called classical Bluetooth. Classical Bluetooth modules generally refer to modules that support Bluetooth protocol 4.0 or lower, including V1.1/1.2/2.0/2.1/3.0. Classical Bluetooth supports audio (HFP/HSP, A2DP) and data (SPP, HID, OPP, PBAP, etc.). It is usually used for transmission of large amount of data, such as music transmission through Bluetooth headset, bluetooth hands-free communication in cars and bluetooth entertainment system in cars. Gradually phased out in the mobile Internet.

Bluetooth Low Power module Refers to a module that supports Bluetooth 4.0 or higher. Bluetooth Low Energy, or BLE for short. Low Power Bluetooth has low power consumption and very low power consumption. However, Low power Bluetooth does not support the audio protocol and is suitable for applications that transmit a small amount of data, such as smart homes, blood pressure monitors, and temperature sensors.

Low power Bluetooth is also divided into two types: single-mode chip and dual-mode chip. Dual-mode chip balances the advantages and disadvantages of the two bluetooth modules, and can transmit audio while consuming low power.

2 Applying for Permission

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <! -- Search bluetooth required, because Bluetooth can be used for location, so location permission required -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
Copy the code

3 Basic Bluetooth operations

3.1 Obtaining a Bluetooth Adapter

// Bluetooth adapter
private val mBluetoothAdapter: BluetoothAdapter by lazy {
    // Initialize the Bluetooth adapter
    val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothManager.adapter
}
Copy the code

3.2 Checking whether Bluetooth is enabled

// Whether to enable Bluetooth
fun isBluetoothEnabled(a):Boolean{
    return mBluetoothAdapter.isEnabled
}
Copy the code

3.3 Enabling Bluetooth

// Enable Bluetooth
fun openBluetooth(a):BluetoothHelper{
    if(! mBluetoothAdapter.isEnabled) {if(! mBluetoothAdapter.enable()){// Try to enable Bluetooth. The return value is whether bluetooth was successfully enabled
            showToast("It is recommended to enable Bluetooth operation")}}return this
}
Copy the code

3.4 Broadcast receiver to detect bluetooth state changes

// Bluetooth state changes the broadcast receiver
private val mBluetoothStateReceiver by lazy{
    object : BroadcastReceiver() {
        override fun onReceive(context: Context? , intent:Intent) {
            when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)) {
                BluetoothAdapter.STATE_ON -> {showToast("Bluetooth enabled.")}
                BluetoothAdapter.STATE_OFF -> {showToast("Bluetooth is off.")}
                BluetoothAdapter.STATE_TURNING_ON -> {showToast("Bluetooth is turning on.")}
                BluetoothAdapter.STATE_TURNING_OFF -> {showToast("Bluetooth is turning off.")}}}}}Copy the code

3.5 Scanning for Nearby Bluetooth Devices

// Search for Bluetooth devices
fun searchDevices(a):BluetoothHelper{
    if (mBluetoothAdapter.isDiscovering){// Cancel the search if you are searching
        mBluetoothAdapter.cancelDiscovery()
    }else{
        mBluetoothAdapter.startDiscovery()
    }
    return this
}
Copy the code

3.6 Stopping Scanning bluetooth Devices

// Stop scanning bluetooth devices
fun stopSearchDevices(a):BluetoothHelper{
    if (mBluetoothAdapter.isDiscovering){
        mBluetoothAdapter.cancelDiscovery()
    }
    return this
}
Copy the code

3.7 The broadcast receiver of a Bluetooth device is detected

// Bluetooth scan broadcast receiver
private val mBluetoothScanReceiver by lazy{
    object : BroadcastReceiver() {
        override fun onReceive(context: Context? , intent:Intent) {
            val action = intent.action
            if (BluetoothDevice.ACTION_FOUND == action) {// Bluetooth device detected
                // Get the detected device
                val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                // Device information
                // device.name? : Indicates the device name
                // device.address: indicates the MAC address of the device
                / / device. BluetoothClass. MajorDeviceClass: device type
            }else if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {// Scan for connected Bluetooth devices (nearby Connected Bluetooth devices, not necessarily connected to the central device)
                val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
            }
        }
    }
}
Copy the code

4 Bluetooth Communication

4.1 UUID

Universally Unique Identifier (UUID) is a hexadecimal number, a Unique Identifier, and a software construction standard. A UUID has 128 bits, or 16 bytes. Since 128 bits are too long to use, common parts are usually preset. The Default UUID for Bluetooth Alliance is 00000000-0000-1000-8000-00805F9b34Fb, which we call the Bluetooth Base UUID. With bluetooth Base UUID, you can use either 16bit or 32bit to represent the actual 128bit UUID. To obtain the actual UUID, move the 16bit or 32bit UUID 96 bits to the left and add the Base UUID.

4.2 Concepts such as services, features, attributes and descriptors

To briefly describe the relationship between services, features, and attributes, imagine a Bluetooth device as a company with several divisions, each of which is a service. Each department has several team members, each team member is a feature, each team member has a different skill, each skill is an attribute. When we need to complete a task, we need to hand the task to the corresponding employee in the corresponding department, that is, find a feature in a service of bluetooth device. To identify each department and department member, the company gives a department number and an employee number, which are service UUids and feature UUIds.

Descriptors are descriptors that are used to define properties of features, descriptors are more verbose than properties.

Central device refers to the client also called host or central device, usually refers to the mobile phone. The central device can scan and connect multiple peripherals, known as Bluetooth devices.

4.3 Obtaining the UUID based on the GATT Discovery Service

Low-power Bluetooth devices use the Generic Attribute Profile (GATT) Bluetooth protocol, which defines bluetooth communication modes based on Service and Characteristic. It should be noted that GATT is exclusive during connection. Once two devices are connected based on GATT, they will stop sending Bluetooth broadcast. Therefore, other Bluetooth devices cannot search for bluetooth devices already connected based on GATT.

4.3.1 GATT Connection (connecting bluetooth Devices)
/ / bluetooth gatt
var mBluetoothGatt: BluetoothGatt? = null
// GATT connects to bluetooth devices
fun connect(device: BluetoothDevice, context: Context) {
    mBluetoothGatt = device.connectGatt(context,false, mGattCallback)
}
Copy the code
4.3.2 Callback passed in during GATT connection
// GATT connection callback
private val mGattCallback by lazy{
    object: BluetoothGattCallback() {
        // Callback when connection state changes
        override fun onConnectionStateChange(gatt: BluetoothGatt? , status:Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            if (newState == BluetoothProfile.STATE_CONNECTED) {// Successful connectionmBluetoothGatt? .discoverServices()// Invoke discovery services (that is, get all services provided by bluetooth devices)
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {// Disconnect the connection}}// Call the discovery service callback
        override fun onServicesDiscovered(gatt: BluetoothGatt? , status:Int) {
            super.onServicesDiscovered(gatt, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {// If the connection is still in the current state
                valbluetoothGattServices = gatt!! .services// Get all the services provided by the Bluetooth device
                // Iterate over all services
                bluetoothGattServices.forEachIndexed { index, bluetoothGattService ->
                    val uuid = bluetoothGattService.uuid // Get the UUID of the service
                    val bluetoothGattCharacteristics = bluetoothGattService.characteristics // Get all the characteristics of the service
                    Log.d(TAG, "Service${index+1}The UUID for:$uuid")
                    Log.d(TAG, "Service${index+1}It has the following characteristics:")
                    // Iterate through all the characteristics of the service
                    bluetoothGattCharacteristics.forEachIndexed { index, bluetoothGattCharacteristic ->
                        Log.d(TAG, "Characteristics${index+1}UUID:${bluetoothGattCharacteristic.uuid}") // Outputs the current characteristic UUID
                        val charaProp = bluetoothGattCharacteristic.properties// Get all attributes of the current feature
                        / / bluetoothGattCharacteristic descriptors / / all the descriptors for current characteristics
                        if (charaProp and BluetoothGattCharacteristic.PROPERTY_READ > 0) {
                            Log.d(TAG, "Characteristics${index+1}Has the read attribute")}if (charaProp and BluetoothGattCharacteristic.PROPERTY_WRITE > 0) {
                            Log.d(TAG, "Characteristics${index+1}Have write attribute")}if (charaProp and BluetoothGattCharacteristic.PROPERTY_NOTIFY > 0) {
                            Log.d(TAG, "Characteristics${index+1}Has notify property")}if (charaProp and BluetoothGattCharacteristic.PROPERTY_INDICATE > 0) {
                            Log.d(TAG, "Characteristics${index+1}Has indicate attribute")}}}}}// Callback while reading data
        override fun onCharacteristicRead(
            gatt: BluetoothGatt? , characteristic:BluetoothGattCharacteristic? , status:Int
        ) {}
        // Callback while writing data
        override fun onCharacteristicWrite(gatt: BluetoothGatt? , characteristic:BluetoothGattCharacteristic? , status:Int) {
            super.onCharacteristicWrite(gatt, characteristic, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // The message was sent successfully
            } else {
                // Failed to send}}// Remote data change callback
        override fun onCharacteristicChanged(
            gatt: BluetoothGatt? , characteristic:BluetoothGattCharacteristic?). {
            super.onCharacteristicChanged(gatt, characteristic) characteristic? .apply {// The characteristics of the data changes
                Log.d(TAG, "onCharacteristicChanged: ${characteristic.uuid}")}}}}Copy the code

A feature has one or more attributes, with four attributes in common.

The property name instructions
read This feature has the ability to read data and can be used to obtain data from bluetooth devices
write This feature can be used to write data to bluetooth devices
notify Bluetooth devices can use this feature to actively send data to us
indicate Bluetooth devices can use this feature to establish a reliable connection to us, which means that after sending us data, we will acknowledge it once to ensure the connection is reliable
4.3.3 Sending Data to bluetooth Device

We can send data to a Bluetooth device through features with the read attribute. Each feature has a different function, so we need to know what function each feature provides by a Bluetooth device. You can easily determine the functions of some features based on the UUID prefix.

Query link:

Blog.csdn.net/qq_43680229…

www.bluetooth.com/specificati…

When the specified feature is found, data is sent to the Bluetooth device through this feature

// Bluetooth Gatt connection service
private var mBluetoothGatt: BluetoothGatt? = null

// A feature
private var mBluetoothGattCharacteristic:BluetoothGattCharacteristic? = null

// Send data
fun sendMess(mess:String){ mBluetoothGattCharacteristic? .setValue(mess)// Modify the value of this featuremBluetoothGatt? .writeCharacteristic(mBluetoothGattCharacteristic)// Write this feature to send data to the Bluetooth device
}
Copy the code