设备配网业务实现

更新时间:2024-01-26 09:32:25下载pdf

本文以常用的蓝牙设备和有线网关设备为例,说明如何配合对应的业务需求,使用配网扩展 SDK 功能,以便您快速了解如何使用业务扩展 SDK。

蓝牙设备

蓝牙设备分类繁多,关于具体类型,参考 蓝牙设备

前置权限

  • 在 Android 12 及更高版本的系统且不需要 ibeacon 类设备广播时,可以仅添加 蓝牙扫描权限

  • 在 Android 11 或更低版本的系统或者需要 ibeacon 类设备广播时,必须添加 蓝牙扫描权限定位权限

若不需要 ibeacon 类设备,则可以在 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"/>

若需要 ibeacon 类设备,则在 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"/>

发现

在权限正确申请以及授予之后,可以在对应功能点使用蓝牙开始搜索:

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) {
                        //发现设备
                    }

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //重复发现
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        //设备能力更新,单蓝牙扫描不会回调此接口方法
                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //发现设备失败
                    }

                    override fun scanFinish() {
                        //搜索结束
                    }

                }

deviceFound 接口成功回调设备信息后,可以根据自定义的产品需求展示对应 UI。

配网

根据扫描到的对应设备类型,有不同的前置条件。若扫描到 ThingDeviceActiveModeEnum.BLE_WIFIThingDeviceActiveModeEnum.MULT_MODE,则需要输入 Wi-Fi 信息获取的页面。关于配网时不同类型的参数传入,参考 蓝牙设备配网

对应设备开始配网时,通过以下回调得到设备配网结果:

    ...
    object : IThingDeviceActiveListener {
        override fun onActiveError(errorBean: ThingDeviceActiveErrorBean) {
            //配网失败

         }

        override fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean) {
             //配网限制

         }

        override fun onActiveSuccess(deviceBean: DeviceBean) {
            //配网成功
       }

       override fun onBind(devId: String) {

       }

       override fun onFind(devId: String) {

        }

​通过 onActiveSuccess 得到 DeviceBean,即说明配网成功。关于 onActiveLimited 方法,配网限制是指两种情况:

  • 有一部分设备是强绑定设备,也就是说需要前一个用户手动移除该设备后,其他用户才可以使用该设备继续配网。如果前一个用户不移除该设备,即使物理重置设备,其他用户也是无法正常配网成功的。
  • 有一部分设备被限制只能在某些对应 App 才可以使用。

在这两种情况下,如果找不到前一个用户或者遗忘了上一个配置账号,可以申请重置解绑。具体功能,参考 常见问题与反馈 UI 业务包

有线网关

前置逻辑

在进行有线连接前,确保手机连接的 Wi-Fi 网络和当前有线网关接入的路由器为同一个

具体情况

情况 1:和其他扫描能力一起扫描周围设备

在业务需求下,可能需要同时扫描多种类型的设备,例如蓝牙和有线网关。这时,出现蓝牙调用扫描方法,但有线网关调用不同的扫描方法,需要通过唯一标识来匹配扫描到的设备和配网的设备。该过程非常复杂,推荐使用涂鸦的 复合扫描能力

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) {
                        //发现设备
            }

            override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //重复发现
            }

            override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        //设备能力更新
            }

            override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //发现设备失败
            }

            override fun scanFinish() {
                        //搜索结束
            }

        }
    )

如此操作,可以将蓝牙和有线网关设备以同一个回调接口和统一的数据实体方式返回,减少了处理数据统一和唯一标识的负责逻辑,方便使用。

情况 2:独立流程扫描

若业务需求中仅有单独的有线网关设备配网需求,则可以直接使用对应的扫描附近有线网关方法。

ThingActivatorCoreKit.getScanDeviceManager().startLocalGatewayDeviceSearch(
    60*1000L,
    object :ThingActivatorScanCallback{
        override fun deviceFound(deviceBean: ThingActivatorScanDeviceBean) {
                        //发现设备
            }

            override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //重复发现
            }

            override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {
                        //设备能力更新
            }

            override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //发现设备失败
            }

            override fun scanFinish() {
                        //搜索结束
            }
    }
)

配网

上述两种业务逻辑扫描后,扫描到的设备都可以使用如下的配网方式,进行配网。

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.WN)
.setActivatorScanDeviceBean(thingActivatorScanDeviceBean) //扫描获取的实体
.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 得到 DeviceBean,说明配网成功。

子设备配网

前置条件

Zigbee 设备依赖 Zigbee 网关连接到云端,因此配网过程中必须连接到某个网关,由网关完成设备激活和消息通知。当前所选网关必须为在线状态。

  1. 过滤当前家庭下的设备。

  2. 找出符合条件的 Zigbee 网关,可能存在多个,并确保其在线。

  3. 选择想要的网关。

  4. 若当前家庭下没有符合条件的网关,应提示客户先添加网关设备。

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

设备搜索

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

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //重复发现
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {

                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //发现设备失败
                    }

                    override fun scanFinish() {
                        //搜索结束
                    }

                }

Zigbee 子设备搜到即为成功,可以使用配网方法直接传入扫描实体结果,拿到对应 DeviceBean 即可。

配网

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.SUB)
.setSubSearchBeans(thingActivatorScanDeviceBeans) //扫描获取的实体
.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 设备配网

前置条件

Matter 设备仅支持 Android M(6.0 API 23)及之上版本。按照 Matter 设备接入准备,配置前置条件。

搜索设备

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

                    override fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean) {
                        //重复发现
                    }

                    override fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean) {

                    }

                    override fun scanFailure(failureBean: ThingActivatorScanFailureBean) {
                        //发现设备失败
                    }

                    override fun scanFinish() {
                        //搜索结束
                    }

                }

配网

val builder = ThingDeviceActiveBuilder()
.setActiveModel(ThingDeviceActiveModeEnum.MATTER_DISCOVERY)
.setActivatorScanDeviceBean(thingActivatorScanDeviceBean) //扫描获取的实体
.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)

回调详情

搜索回调

interface ThingActivatorScanCallback {

    /**
     * 设备发现
     */
    fun deviceFound(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * 设备能力更新
     */
    fun deviceUpdate(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * 重复上报
     */
    fun deviceRepeat(deviceBean: ThingActivatorScanDeviceBean)

    /**
     * 搜索结束
     */
    fun scanFinish()

    /**
     * 搜索错误
     */
    fun scanFailure(failureBean: ThingActivatorScanFailureBean)

}

deviceUpdate 方法有何作用,何时会触发?

当您使用复合配网能力,例如您同时开启蓝牙和闪电配网,先通过蓝牙搜到,则会通过 deviceFound 返回。之后通过闪电搜到后,则会通过 deviceUpdate 返回。只需要将之前保存的 scanDeviceBean 替换为新返回的实体即可。

deviceRepeat 方法有何作用,何时会触发?

目前仅在蓝牙模式下,App 可能会重复收到设备的广播包,则会通过 deviceRepeat 方法回调出对应重复扫描到的设备。

配网回调

interface IThingDeviceActiveListener {
    /**
     * 发现设备
     * @param devId 设备 ID
     */    fun onFind(devId: String)

    /**
     * 绑定设备
     * @param devId 设备 ID
     */    fun onBind(devId: String)

    /**
     * 激活成功
     * @param deviceBean 设备数据模型
     */
    fun onActiveSuccess(deviceBean: DeviceBean)

    /**
     * 激活失败
     *
     * @param errorBean 错误信息
     */
    fun onActiveError(errorBean: ThingDeviceActiveErrorBean)

    /**
     * 被限制激活,例如强绑定,双向绑定,游客模式等特殊情况
     *
     * @param limitBean 包含设备简单信息
     */
    fun onActiveLimited(limitBean: ThingDeviceActiveLimitBean)
}

什么是强绑定?如何打开或关闭?

进行以下操作,开启和关闭设备强绑定功能。

  1. 登录 涂鸦 IoT 开发平台产品开发

  2. 选择目标产品,单击 操作 栏的 继续开发

  3. 功能定义 页面,下滑页面找到 高级功能 里的 设备绑定模式,单击 操作 栏的开关,开启或者关闭该功能。

    设备配网业务实现

什么是双向绑定?

PID 与 App 存在两个维度的限制规则。简而言之,在 PID 下可配置该 PID 可被哪个 App 绑定,在 App 下可配置该 App 允许哪些设备连入。只有同时满足 PID 允许该 App 绑定,并且 App 也允许该 PID 接入的情况下,设备绑定才能成功。

在默认情况下,PID 与 App 均不存在任何限制规则,可任意连接。

参考文档