Device Pairing

Last Updated on : 2024-01-26 09:53:36download

This topic describes how to implement the Device Pairing BizBundle SDK to meet your business needs, using common Bluetooth devices and wired gateways as examples.

Bluetooth device

There are various types of Bluetooth devices. See Bluetooth Devices for details.

Prerequisites

  • If your app on Android 12 or later does not support iBeacon devices, you only need to include the Bluetooth scan permission.

  • If your app is on Android 11 or earlier or supports iBeacon devices, you need to include the Bluetooth scan and location permissions.

If iBeacon is not supported, add the following permissions in AndroidManifest:

    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>

If iBeacon is supported, add the following permissions in AndroidManifest:

    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

Discover

After the necessary permissions are granted, the app can start Bluetooth device discovery.

val scankey = ThingActivatorCoreKit.getScanDeviceManager()
            .startBlueToothDeviceSearch(
                25 * 1000L,
                arrayListOf(ScanType.MESH, ScanType.SIG_MESH, ScanType.SINGLE, ScanType.THING_BEACON),
                object : ThingActivatorScanCallback {
                    override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        // Device discovery
                    }

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        // Repeated discovery
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        // Device capability update. This method will not be called back during a scan for a single Bluetooth device.
                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        // Device discovery failed
                    }

                    override fun scanFinish() {
                        // Search finished
                    }

                }

After the deviceFound callback returns the device information, your app will present the UI accordingly.

Pairing

The prerequisites vary by device type. If ThingDeviceActiveModeEnum.BLE_WIFI or ThingDeviceActiveModeEnum.MULT_MODE is discovered, the page prompting the user to enter Wi-Fi credentials is required. For more information about pairing parameters, see Bluetooth Device Pairing.

When a device starts pairing, you can get the result through the following callback.

    ...
    object : IThingDeviceActiveListener {
        override fun onActiveError(errorBean: ThingDeviceActiveErrorBean) {
            // Pairing failed.

         }

        override fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean) {
             // Pairing restricted.

         }

        override fun onActiveSuccess(deviceBean: DeviceBean) {
            // Pairing succeeded.
       }

       override fun onBind(devId: String) {

       }

       override fun onFind(devId: String) {

        }

onActiveSuccess returns DeviceBean, indicating pairing succeeds. The onActiveLimited method exposes two types of limitations.

  • Devices of strong binding must be manually removed by the current user before being paired with another user. Otherwise, even if the device is physically reset, it still cannot be paired.
  • Devices can only be paired with specific apps.

In both cases, if the device cannot be unpaired from the associated account, the user can request a reset to unbind the device. For more information, see FAQ UI BizBundle.

Wired gateway

Prerequisites

The mobile phone and the wired gateway are connected to the same router.

Scan

Case 1: Scan for devices along with other scan capabilities.

Your app needs to scan for multiple types of devices at the same time, such as Bluetooth and wired gateways. In this case, Bluetooth scan and wired gateway scan methods are called, requiring a unique identifier to match the discovered devices with the paired ones. Given the complexity of this process, it is recommended to adopt composite scan.

val scanKey = ThingActivatorCoreKit.getScanDeviceManager()
    .startScan(
        ThingActivatorScanBuilder().apply {
            setScanTypeList(arrayListOf(ThingActivatorScanType.LOCAL_GATEWAY,ThingActivatorScanType.BLUETOOTH))
            setBlueScanDeviceTypeList(arrayListOf(ScanType.MESH, ScanType.SIG_MESH, ScanType.SINGLE, ScanType.THING_BEACON))
            setMillisTimeOut(100*1000L)
        },
        object :ThingActivatorScanCallback{
            override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device discovery
            }

            override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //Repeated discovery
            }

            override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device capability update
            }

            override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //Device discovery failed
            }

            override fun scanFinish() {
                        //Search finished
            }

        }
    )

Composite scan enables the discovered Bluetooth device and wired gateway to be returned with the same callback and unified data entity, eliminating the need for data unity and unique identifiers.

Case 2: Independent scanning

If your app only needs to scan for wired gateways, you can use the respective scan method.

ThingActivatorCoreKit.getScanDeviceManager().startLocalGatewayDeviceSearch(
    60*1000L,
    object :ThingActivatorScanCallback{
        override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device discovery
            }

            override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //Repeated discovery
            }

            override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device capability update
            }

            override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //Device discovery failed
            }

            override fun scanFinish() {
                        //Search finished
            }
    }
)

Pairing

After a device is discovered using either of the scan methods mentioned above, it can be paired through the following method.

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.WN)
.setActivatorScanDeviceBean(thingActivatorScanDeviceBean) //Scan the obtained entity.
.setTimeOut(timeout)
.setListener(object : IThingDeviceActiveListener {
override fun onFind(devId: String) {

}
override fun onBind(devId: String) {

}

override fun onActiveSuccess(deviceBean: DeviceBean) {

}

override fun onActiveError(errorBean: ThingDeviceActiveErrorBean) {

}

override fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean) {

}
})

val activeManager = ThingActivatorCoreKit.getActiveManager().newThingActiveManager()
activeManager.startActive(builder)

onActiveSuccess returns DeviceBean, indicating pairing succeeds.

Sub-device

Prerequisites

A Zigbee device relies on a Zigbee gateway to connect to the cloud. Therefore, the pairing process requires a specific gateway that processes device activation and notifications. The target gateway must be online.

  1. Filter the devices in the current home.

  2. Find suitable Zigbee gateways and make sure they are online.

  3. Select the preferred gateway.

  4. If there is no suitable gateway, prompt the user to add one.

    val activedGatewayList: MutableList<DeviceBean> = ArrayList()
    val list = getDeviceList()
    for (deviceBean in list) {
        if (deviceBean.hasConfigZigbee()) {
            activedGatewayList.add(deviceBean)
        }
    }
    

Search

val scankey = ThingActivatorCoreKit.getScanDeviceManager()
            .startGatewaySubDeviceSearch(
                gatewayId,
                25 * 1000L,
                object : ThingActivatorScanCallback {
                    override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device discovery
                    }

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //Repeated discovery
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {

                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //Device discovery failed
                    }

                    override fun scanFinish() {
                        //Search finished
                    }

                }

After a Zigbee sub-device is discovered, pass in the result with the pairing method to obtain the DeviceBean.

Pairing

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.SUB)
.setSubSearchBeans(thingActivatorScanDeviceBeans) //Scan the obtained entity.
.setTimeOut(timeout)
.setListener(object : IThingDeviceActiveListener {
override fun onFind(devId: String) {

}

override fun onBind(devId: String) {

}

override fun onActiveSuccess(deviceBean: DeviceBean) {

}

override fun onActiveError(errorBean: ThingDeviceActiveErrorBean) {

}

override fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean) {

}
})

val activeManager = ThingActivatorCoreKit.getActiveManager().newThingActiveManager()
activeManager.startActive(builder)

Matter device

Prerequisites

Android 6.0 (API level 23) and later support Matter devices. see Prepare for Integration with Matter Device to configure the prerequisites.

Search

val scankey = ThingActivatorCoreKit.getScanDeviceManager()
            .startMatterDeviceSearch(
                25 * 1000L,
                object : ThingActivatorScanCallback {
                    override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        //Device discovery
                    }

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //Repeated discovery
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {

                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //Device discovery failed
                    }

                    override fun scanFinish() {
                        //Search finished
                    }

                }

Pairing

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.MATTER_DISCOVERY)
.setActivatorScanDeviceBean(thingActivatorScanDeviceBean) //Scan the obtained entity.
.setTimeOut(timeout)
.setRelationId(homeId)
.setListener(object : IThingDeviceActiveListener {
override fun onFind(devId: String) {

}
override fun onBind(devId: String) {

}

override fun onActiveSuccess(deviceBean: DeviceBean) {

}

override fun onActiveError(errorBean: ThingDeviceActiveErrorBean) {

}

override fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean) {

}
})

val activeManager = ThingActivatorCoreKit.getActiveManager().newThingActiveManager()
activeManager.startActive(builder)

Callbacks

Search callback

interface ThingActivatorScanCallback {

    /**
     * Device discovery
     */
    fun deviceFound(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * Device capability update
     */
    fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * Repeated reporting
     */
    fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * Search finished
     */
    fun scanFinish()

    /**
     * Search error
     */
    fun scanFailure(failureBean: ThingActivatorScanFailureBean)

}

What is the purpose of deviceUpdate and when does it get triggered?

If you are using the composite scan with both Bluetooth and Pegasus pairing enabled, the device will be returned through deviceFound when it is first discovered over Bluetooth. After the device is then discovered by Pegasus pairing, it will be returned through deviceUpdate. Replace the previously saved scanDeviceBean with the new entity.

What is the purpose of deviceRepeat and when does it get triggered?

In Bluetooth mode, the app may receive duplicate advertising packets from the device. The deviceRepeat callback will return the repeatedly discovered device.

Pairing callback

interface IThingDeviceActiveListener {
    /**
     * Device discovery
     * @param devId Device ID
     */    fun onFind(devId: String)

    /**
     * Bind the device.
     * @param devId Device ID
     */    fun onBind(devId: String)

    /**
     * Activation succeeded.
     * @param deviceBean Device data model.
     */
    fun onActiveSuccess(deviceBean: DeviceBean)

    /**
     * Activation failed.
     *
     * @param errorBean Error message
     */
    fun onActiveError(errorBean: ThingDeviceActiveErrorBean)

    /**
     * Activation is restricted, due to such as strong binding, two-way binding, or guest mode.
     *
     * @param limitBean Includes basic device information
     */
    fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean)
}

What is strong binding? How can I enable or disable it?

Perform the following steps to enable or disable strong binding for a product.

  1. Log in to the Tuya IoT Development Platform.

  2. Select a product and click Develop in the Operation column.

  3. In the Function Definition step, scroll down to Advanced Functions and find Device Binding Mode. Toggle it on or off as desired.

    Device Pairing

What is two-way binding?

Device binding is restricted by both the PID and the app. You can specify the app that a PID can be bound with and the device that an app can be connected to. A device can only be bound when both the app and the device meet the restriction.

By default, there are no restrictions for both the PID and app, allowing them to be connected freely.

Reference