DEV Community

HarmonyOS
HarmonyOS

Posted on

How to Establish a Classic Bluetooth Connection Using the Virtual MAC Address of a Connected BLE Bluetooth Device?

Read the original article:How to Establish a Classic Bluetooth Connection Using the Virtual MAC Address of a Connected BLE Bluetooth Device?

Context

Bluetooth technology is a wireless communication technology that can transmit data over short distances. Currently, Bluetooth is divided into two common technical categories: traditional Bluetooth (BR/EDR) and low-energy Bluetooth (BLE). The distinction between the two types of Bluetooth can be referred to in the overview of Bluetooth service development.

In BLE Bluetooth, the ScanFilter parameter can be used to precisely locate the BLE Bluetooth device that needs to be connected.

Classic Bluetooth scanning cannot configure filter parameters and usually can only determine the target device by calling the getRemoteDeviceName interface to obtain the device name through the scanned virtual MAC address.
If the peer device supports both classic Bluetooth and BLE, establishing a Bluetooth pairing via the BLE Bluetooth virtual MAC address will also complete the classic Bluetooth pairing.

Description

When multiple Bluetooth devices with the same name are present in the vicinity, how can one accurately identify the device currently connected via BLE in the classic Bluetooth scan list and further establish a classic Bluetooth connection?

Solution

Use the virtual MAC address of the connected BLE device to call the pairDevice interface to initiate pairing. After the pairing is completed, the pairing list will not only include the pairing information of BLE but also the pairing information of classic Bluetooth. By calling the getPairedDevices interface, the virtual MAC address of classic Bluetooth can be directly obtained, and then this MAC address can be used to establish a classic Bluetooth connection.

Reference sample code:

import socket from '@ohos.bluetooth.socket';
import connection from '@ohos.bluetooth.connection';
import { ble } from '@kit.ConnectivityKit';
import { abilityAccessCtrl } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  @State ble_address: string = '';
  @State name: string = 'The name of the filtration equipment';
  private context: Context = this.getUIContext().getHostContext() as Context;

  aboutToAppear() {
    const AtManager = abilityAccessCtrl.createAtManager();

    AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.ACCESS_BLUETOOTH'])
      .then(data => {
        let result: Array<number> = data.authResults;
        let hasPermissions1 = true;
        result.forEach(item => {
          if (item === -1) {
            hasPermissions1 = false;
          }
        })
        if (hasPermissions1) {
          console.info("hasPermissions1")
        } else {
          console.info("not hasPermissions1")
        }
      }).catch((error:BusinessError) => {
        console.error(JSON.stringify(error))
    });
  }

  connect(deviceId: string) {
    let sppOption: socket.SppOptions = {
      // The UUID address here is defined when the socket server is created.
      uuid: '0000xxxx-0000-1000-8000-00805f9b34fb',
      secure: true,
      type: 0
    };
    console.log("Prepare to connect classic Bluetooth: " + deviceId)
    setTimeout(() => {
      socket.sppConnect(deviceId, sppOption, (code, socketID) => {
        console.log('ConnectSPP: ' + code + "socketID:" + socketID);

      });
    }, 1000)
  }

  pinRequired() {
    connection.on('pinRequired', (onReceiveEvent) => {
      connection.on("bondStateChange", (data: connection.BondStateParam) => {
        console.info('pair state = ' + data);
        if (data.state == 2) {
          // After the pairing is completed, re-fetch the pairing list information. At this point, the pairing list contains both the BLE pairing information and the classic Bluetooth pairing information for the device.
          let devices: Array<string> = connection.getPairedDevices();
          for (let i = 0; i < devices.length; i++) {
            console.log("Paired MAC:" + devices[i])
            let dev: string = devices[i]
            // 4. Identify the classic Bluetooth MAC address by using the BLE Bluetooth MAC address.
            if (dev != this.ble_address) {
              let n: string = connection.getRemoteDeviceName(devices[i])
              console.warn("After pairing, start connecting:" + n + "mac:" + devices[i])
              //5. Obtain the device name through the classic Bluetooth MAC address, and then use this name for a secondary match to identify the device.
              if (n == this.name) {
                connection.off("bondStateChange")
                // After determining the device, initiate a classic Bluetooth connection.
                this.connect(devices[i])
              }
            }
          }
        }
      })
    });
    ble.on('BLEDeviceFind', (data) => {
      for (let i = 0; i < data.length; i++) {
        let name: string = data[i].deviceName
        console.warn("Device discovered: " + name + ", address:" + data[i].deviceId)
        ble.stopBLEScan();
        ble.off('BLEDeviceFind')
        // After discovering the device, first save the device name.
        this.ble_address = data[i].deviceId;
        let devices: Array<string> = connection.getPairedDevices();
        let index = devices.indexOf(data[i].deviceId)
        // 2.1 Check the pairing list; if the device is not paired, initiate the pairing process first.
        if (index < 0) {
          console.warn("Preparing for pairing:" + name)
          connection.pairDevice(data[i].deviceId).then(() => {
            console.warn("Enter Pairing:" + name)
          })
        } else {
          console.warn("Paired" + name)
          // 2.2 If the device has already been paired, simply locate the classic Bluetooth MAC address of the paired device in the pairing list and initiate the connection.
          for (let i = 0; i < devices.length; i++) {
            console.log("Paired mac:" + devices[i] + "Equipment Name:" + name)
            let dev: string = devices[i]
            if (dev != this.ble_address) {
              let n: string = connection.getRemoteDeviceName(devices[i])
              console.warn("After pairing, start connecting n:" + n + "mac:" + devices[i])
              if (n == name) {
                connection.off('pinRequired')
                this.connect(devices[i])
              }
            }
          }
        }
      }
    });
    // 1. Initiate a BLE scan using the device name as the filtering parameter to obtain the MAC address of the peer BLE Bluetooth device.
    ble.startBLEScan([{
      name: this.name
    }], {
      interval: 500,
      dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
      matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE,
    })
  }

  build() {
    Column() {
      Button('Scan BLE to initiate pairing - connect to classic Bluetooth').onClick(() => {
        this.pinRequired()
      })
    }
    .width('100%')
    .height('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Q: After initiating device pairing using connection.pairDevice and successfully completing it, how can I cancel the pairing through code?

A: The system currently does not provide an interface for canceling Bluetooth pairing externally. You can try manually canceling the pairing.

Q: How to parse the data in the scan result, such as 0,"1":255,"2":34...}, into the format xxxx-xxxx-xxxx-xxxx?

A: You can refer to the parseScanResult function provided in API12 for enabling and disabling scanning to get the parsing method.

Q: Can the uuid in HarmonyOS be used for connections with iOS and Android?

A: The uuid is a parameter defined by the manufacturer and can be used for connections with iOS and Android.

Q: How to implement long-term listening to messages sent by the device?

A: You can subscribe to the characteristic value change events of the Bluetooth Low Energy device through on('BLECharacteristicChange').

Q: If an application stays in the background for a long time and is still connected to a device, will the process be killed by the system? Are there any measures to keep it alive?

A: Yes, you can apply for long-term task preservation for Bluetooth-related services.

Q: In the solution, the device is first connected via BLE, and then a classic Bluetooth connection is established. Does it support the method of first connecting via classic Bluetooth and then establishing a BLE connection?

A: Currently, it does not support the method of first establishing a classic Bluetooth connection and then establishing a BLE connection.

Key Takeaways

  • First, connect two devices via BLE
  • Obtain the MAC address using the getPairedDevices interface
  • Use this MAC address to establish a classic Bluetooth connection.

Written by Mehmet Karaaslan

Top comments (0)