Android 蓝牙Mesh组网代码详解

前言

  上面的几篇文章都是在说Android网络编程方面的内容,我本来就有打算做成一个系列。但最近因为工作的原因,一直在研究蓝牙mesh组网对蓝牙设备进行控制,研究了近两个星期,总算有了点自己的理解。先对蓝牙Mesh 组网做一个总结,下面的文章会继续写Android 网络编程方面的内容。网上关于Mesh 组网的理论解释倒是很多,但是很少有关于Android 代码具体实现的,这篇文章将基于Android Mesh 组网的代码实现进行讲解,希望能带给大家一些帮助。

Mesh组网基本理解

  蓝牙技术联盟写了解密蓝牙mesh系列,一共10篇文章 讲述了蓝牙mesh理论内容以及整个流程 ,想要详细了解的可以点击查看。下面我们简单介绍下Mesh组网到底是什么:
在这里插入图片描述
  MESH是一种新型的无线网络架构,蓝牙Mesh组网内每台设备均通过低功耗蓝牙无线连接进行通信,而这些设备被称之为节点。每个节点都能发送和接收消息,消息能够在节点之间被中继,从而让消息传输至比无线电波正常传输距离更远的位置。归结成一句话:蓝牙Mesh组网 就是一种在同一个网络内任意蓝牙设备都进行数据交互的技术。这样的话,APP 只要能发现组网内的任何一台设备,就能由设备发现组网内的其他Mesh设备,并和任何一台设备建立连接并控制。


  其实,我对蓝牙Mesh 的组网也仅仅限于上面的理解。作为一个Android 开发人员,我更关注的是Android 代码到底如何去实现蓝牙设备的组网。在网上也找到了一些项目和代码,仔细研究了下也是很迷茫。后来找到了泰凌微提供的蓝牙Mesh灯项目以及开放的Mesh 组网流程的源码,才真正的算是实现了Android 组网。我将这个资料上传到了百度网盘 ,提取码是6i57。也上传到了CSDN资源,点击即可下载,里面有一个Android Mesh组网的项目及具体源码、SDK开发手册以及加密手册。当然,这个项目的知识产权还是归泰凌微所有,如果有任何侵权行为联系本人,本人将立即下架这两个项目,发布的原因还是想给大家普及一下Android 如何实现Mesh 组网的,没有任何盈利行为。

扫描设备

  因为下面的分析是基于上面项目的代码去分析的,所以需要你们下载下来项目跑起来。
  无论是连接已经完成组网设备还是将一个待组网设备进行组网,APP 做的第一步永远是扫描,扫描到所有的蓝牙设备,然后拿到指定的Mesh组网的设备进行组网操作。下面是代码分析:

在扫描界面执行: startScan(params) 启动扫描,然后会执行一个循环任务EventLoopTask,在循环任务中每200毫秒查询一次状态,然后 startLeScan() 方法中判断设备是否正在扫描,如果没有,则在LeBluetooth类中开启扫描startScan()
在注册TelinkLightService的时候,会创建一个LightAdapter并启动,会设置设备的扫描结果回调setLeScanCallback(LeScanCallback callback),然后当上面的扫描开启后,会将扫描得到的设备返回的这个回调中的onLeScan()方法中.在这个方法中,会先对设备本身返回的信息进行处理和判断,符合标准的设备返回到在扫描界面设置监听的performed方法中的,然后执行onLeScan(),扫描这一步就完成了。
扫描完拿到三个信息 device rssi 以及scanRecord 。蓝牙设备的地址可以根据device.getAddress()直接获取 比如说我拿到的灯设备 scanRecord 的数据如下:
02:01:05:05:09:4D:65:73:68:09:FF:11:02:11:02:35:43:68:38:1E:FF:11:02:11:02:35:43:68:38:21:43:01:35:00:10:19:44:45:4C:20:68:73:65:4D:20:47:53:54:42:4A:00:00:00:00:00:00:00:00:00:00:00:00
​ 在
DefaultAdvertiseDataFilter
类中可以看到 有meshNamemeshAddressmeshUUIDproductUUID等数据。很明显我们可以根据这些数据分析当前设备在哪个mesh 下,地址又是什么。

  总结:执行SDK提供的开始扫描接口startScan()的时候,可以从设备发现的回调中拿到具体的蓝牙设备和广播。mac 地址和设备名称等信息可以从设备中拿到,而设备所属的Mesh 组网名称、设备的MeshAddress(设备在组网内的唯一标识,通讯地址)等信息可以在广播中获取到。其中productUUID是指的产品类型,可以在设备中自定义这个类型。而meshUUID则是厂商默认设置的值,至于status 这个值是厂商的预留值,也是可以在设备中自定义的信息,总的来说,在这个APP 的代码中,并没有实际用到这三个参数。

组网

meshAddress

   在onLeScan() 方法里,会调用一个mesh.getDeviceAddress() 的方法,这个方法很重要,这里面拿到的meshAddress就是后面要修改新加入组网设备的meshAddress,他在后面会被设为newMeshAddress然后保存下来。因为在蓝牙mesh组网下,meshAddress是用来确定设备的,他在这个组网内是唯一固定的。那这个方法实现的逻辑是怎样的呢?比如说要加入一个新设备要加入当前的组网,不管他原先的meshAddress是多少 ,只看我当前组网下的meshAddress。比如说有两个设备,地址分别是 1、3,在这个方法里,会遍历1-254的值,然后就会返回一个2 ,这个2就是要设置的新meshAddressmeshAddress的范围就是1-254,当然了你也可以修改这个范围。

添加与重连

  组网的时候,SDK提供了两个接口,一个是添加新的设备进行组网,调用的是TelinkLightService.Instance().updateMesh(params);更新接口,这个接口能够更改设备本身出厂时的参数meshNamepasswordltk三个信息,这三个信息修改成功, 就标志着设备已经组⽹网成功,将设备成功加入到新的组网下。另一个是如果当前设备的meshName,password是你要组⽹网的名称,可以执⾏**TelinkLightService.Instance().autoConnect(connectParams);**自动重连接口,直接把APP 跟设备连接起来。

UUID

  在组网之前,我们需要知道UUIDUUID是根据一定算法,计算得到的一长串数字,这个数字的产生使用了多种元素,所以使得这串数字不会重复,每次生成都会产生不一样的序列,所以可以用来作为唯一标识。
  在蓝牙协议中,UUID被用来标识蓝牙设备所提供的服务,并非是标识蓝牙设备本身哦,一个蓝牙设备可以提供多种服务,比如A2DP(蓝牙音频传输)、HEADFREE(免提)、PBAP(电话本)、SPP(串口通信)等等,每种服务都对应一个UUID,其中在蓝牙协议栈里,这些默认提供的profile是都有对应的UUID的,也就是默认的UUID,比如SPP00001101-0000-1000-8000-00805F9B34FB就是一个非常 well-known的UUID,基本上所有的蓝牙板不修改的话都是这个值。但是,不同的设备也不同的UUID,如果是与一个蓝牙开发板进行通信,需要APP 和 蓝牙设备的UUID 保持一致。而APP代码中的UuidInformation类里面就可以设置你要控制的低功耗蓝牙设备的UUID。一般都要修改服务状态通知控制OTA加密这五个UUID。下面进行的登录,修改参数、控制设备等等操作都需要UUID 的验证。

  下面我们主要讲一下更新接口的实现,其实自动重连接口就是比更新接口少了修改设备信息这一步。

连接

   发现设备后,拿到要组网的设备的本身的信息,然后就开始进行连接了。其实就是走的低功耗蓝牙设备的connectGatt(this, false, mGattCallback); 连接方法。

更新参数执行updateMesh()⽅法来更新设备的meshName、password、ltk,也还是会执⾏行一个循环任务 EventLoopTask,在循环任务中每200毫秒查询一次状态,然后update()方法中进行connect(),然后在LightController类中执行connect(),最终会执行Peripheral类的connect()⽅法,然后通过此BluetoothDeviceconnectGatt(this, false, mGattCallback)方法获取设备连接。⽆论当连接上设备或者失去连接时会回调onConnectionStateChange(),当连接成功后调用discoverServices函数尝试发现服务,当设备是否找到服务时,会回调onServicesDiscovered()函数,然后会在LightPeripheral类中的onServicesDiscovered()回调给LightController,最后发给 LightAdapterCONNECT_SUCCESS. 连接成功后会执行登录的⽅法。

登录

  登录的过程是一个比较复杂的过程,涉及到多次的加密验证。这个验证之间的过程就会用到我们上面说的服务特征值UUID以及加密特征值UUID
  在LightAdapter类执行登录login的方法,最终的实现是在LightController类中的login方法.参考了BLE_LIGHT加密流程简介V1.9.pdf文档,登录校验的具体实现如下:

  1. 根据 meshName、password、randm 这 3 个参数生成一个 sk,然 后把 randm 和生成的 sk 的低 8 个 byte(校验用)一起发送给设备
  2. 设备获取到发过来的 randm 并和 BLE Light 本身存储的 meshname 和 password 进行加密获取一个 sk,将生成的 sk 的低 8Byte 和 Master 发过来的 sk 进行比较,如果正确,则表示认证成功。
  3. 设备也会随机生成8Byte的 rands、以及本地存储的 mesh name、password 这 3 个参数加密生成一个 sk,会把sk 和 rands 传给APP,然后在本地会根据 randm、rands、meshname、password 共同生成一个新的sk,后续的加密和解密都将使用刚刚生成的 sk。
  4. APP 拿到设备发过来的sk后会进行校验,校验成功后获取8Byte的 rands,并根据该 rands 和randm、mesh name、password共同生成一个 sk,此时,APP 和 设备 两边的 sk 都是一样的,也就可以进行正常的加密和解密,同时的,登录的过程也就完成了。

修改信息

  我上面说过,加新设备进行组网的过程就是修改meshNamepasswordltk,这三个参数的过程。其实这么说也并不是特别准确,其实在修改这三个参数之前还需要对比meshAddress(就是扫描设备拿到的meshAddress)与上面保存的newMeshAddress 要不要修改,因为我们上面说过,因为在蓝牙mesh组网下,meshAddress是用来确定设备的,他在这个组网内是唯一固定的。修改成功后才能进行下面三个参数的修改,这三个参数修改完成就标志这新设备已经成功组网。
  上面我说到LTK,可能有的朋友不知道这个是什么东西,meshNamepassword都很好理解,是mesh 组网的名称和密码,而LTK 是节点之间的通信秘钥,只要LTK一致,同一个组网间的设备就能正常通信。但是在代码中updateMesh(params)方法中,我们并没有给LTK赋值,所以当我们设置的时候将使用厂商默认LTK值。如果要修改自定义的LTK,可以调用params.setLtk() 方法进行赋值。
  下面是代码分析:

登录的sk校验会出现在LightController类的LoginCommandCallback里面,然后在LightAdapter里面的ConnectionListener() 返回一个登录成功或者失败的回调。登录成功后要修改meshName, password, ltk这三个信息,这三个信息就是组网的标志。修改的过程发生在LightController类的reset方法,会先判断设备的meshAddress要不要修改,如果要修改的话就先修改meshAddress,然后在onDeviceAddressNotify()方法里继续执行reset方法。通过加密的方法将这三个参数发送给设备,具体的加密过程也可以参照上面的BLE_LIGHT加密流程简介V1.9.pdf 文档去解析下,最后发发送了一个重新检查的命令,等待设备解密并修改完成发出的确认信息就完成了信息的修改。修改命令的回调都在ResetCommandCallback里,收到最后的TAG_RESET_MESH_CHECK的确认后,继续往下执行,会发出一个RESET_MESH_SUCCESS事件 ,然后在ResetMeshListener的回调里设置STATUS_UPDATE_MESH_COMPLETED,表明已完成信息更新,扫描到的这个设备组网完成,最后在扫描界面onDeviceStatusChanged的方法里面继续执行加灯操作,直到扫不到设备。

控制与接收设备数据

  控制与接收设备数据这里的代码就比较简单了,都有特定的方法去实现,唯一需要注意的一点就是发送数据的协议,一定要是当前设备的协议,否则无法进行控制。具体的实现可以参照下面的流程:
在这里插入图片描述

总结

  以上就是蓝牙Mesh 组网的整个流程了,下面引用一张我们ios 同事画的流程图理解一下:
在这里插入图片描述
  喜欢这篇文章或者对你有帮助的话希望能点个赞!


2020年2月23日补充

  我写了这篇博客有很多人联系我讨论蓝牙Mesh 组网的问题,非常感谢大家的信任。但因为这篇文章内容已经有点久远了,并且我本人在18年底就换了份工作,蓝牙Mesh网关之后就没有搞过了,有很多问题帮助不了大家,真的很抱歉。建议大家如果看了这篇文章有帮助的话尽量联系下泰凌威或者类似的蓝牙厂商,就算不接入他们看看他们的开发文档也是很有帮助的,毕竟他们才是专业的。而我当时只不过是一个开发接入者,把他们的实现用自己的思路整理了下,然后分享出来。真心希望大家能获取到自己想要的答案,再次感谢。

  • 25
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: Qt是一种跨平台的应用程序框架,能够用于开发各种类型的应用程序,包括蓝牙低功率(BLE)应用。在Qt中,有一组蓝牙API可以用于BLE开发。 首先,我们需要在Qt中配置蓝牙模块。为了使用蓝牙功能,我们需要安装Qt的蓝牙模块。在Qt版本5.2及以上,该模块已经包含在Qt中。如果使用的是早期版本的Qt,我们需要手动安装蓝牙模块。 接下来,我们可以开始BLE开发代码。在Qt中,我们可以使用QBluetooth类来实现BLE的相关功能。QBluetooth类提供了一组方法,用于执行BLE设备的扫描、连接、数据传输等操作。 首先,我们需要创建一个QBluetoothDeviceDiscoveryAgent对象,并连接其信号与槽函数,以便接收设备的发现信息。通过调用start()函数,可以开始设备的扫描。扫描结果可以通过deviceDiscovered信号获取。 当发现所需的BLE设备后,我们可以使用QBluetoothDevice类的相关方法来连接设备。我们可以创建一个QBluetoothSocket对象,并使用connectToService函数来连接设备。在连接成功后,我们可以使用QBluetoothSocket对象的write和read函数来发送和接收数据。 除了连接和数据传输,Qt还提供了一些其他的BLE功能,比如获取设备的服务和特征值。我们可以使用QBluetoothDeviceInfo类的相关方法来获取和解析设备的服务与特征值。 总结来说,Qt提供了一组蓝牙API,可用于开发蓝牙低功率(BLE)应用。通过使用Qt的蓝牙模块,我们可以轻松地扫描、连接、监听、写入和读取数据等操作。使用Qt进行BLE开发,可以实现跨平台的蓝牙应用程序,方便快捷。 ### 回答2: Qt是一个流行的跨平台应用框架,它提供了丰富的开发工具和库,可以用于开发各种应用程序,包括蓝牙低功率(BLE)应用。下面是一些关于Qt蓝牙低功率开发的代码示例。 首先,我们需要包含Qt的蓝牙库: ```cpp #include <QLowEnergyController> #include <QLowEnergyService> #include <QBluetoothDeviceInfo> ``` 接下来,我们可以使用QLowEnergyController来搜索和连接附近的蓝牙设备: ```cpp QLowEnergyController *controller = new QLowEnergyController(QBluetoothAddress(deviceAddress), this); connect(controller, &QLowEnergyController::connected, this, &MyClass::deviceConnected); controller->connectToDevice(); ``` 在连接到设备后,我们可以使用QLowEnergyService来与设备上的服务进行交互: ```cpp QLowEnergyService *service = controller->createServiceObject(QBluetoothUuid(serviceUuid), this); connect(service, &QLowEnergyService::stateChanged, this, &MyClass::serviceStateChanged); service->discoverDetails(); // 发现服务的详细信息 ``` 一旦发现了服务的详细信息,我们可以通过QLowEnergyCharacteristic来读取和写入特征值: ```cpp QLowEnergyCharacteristic characteristic = service->characteristic(QBluetoothUuid(characteristicUuid)); service->readCharacteristic(characteristic); // 读取特征值 service->writeCharacteristic(characteristic, data); // 写入特征值 ``` 以上是一些基本的Qt蓝牙低功率开发代码示例。当然,具体的开发过程还涉及更多的细节和业务逻辑,如错误处理、通知和指示等。如果您想深入了解Qt蓝牙低功率开发,建议参考Qt官方文档和示例代码。 ### 回答3: QT是一种跨平台的开发框架,可以用于开发各种类型的应用程序,包括蓝牙低功率(BLE)应用。在QT中进行BLE开发的代码主要涉及以下几个方面。 首先,需要使用QT的蓝牙API来进行BLE的相关操作。这些API包括与BLE设备进行连接、断开连接,以及发送和接收BLE数据等功能。通过使用这些API,我们可以在应用程序中实现BLE设备的搜索,连接和数据交互等操作。 其次,需要创建一个BLE设备的模型,并处理BLE设备的相关事件。通过将BLE设备信息存储在模型中,我们可以方便地管理和操作BLE设备。同时,需要处理与BLE设备相关的事件,如设备连接成功、断开连接、以及接收到BLE数据等事件。 此外,还需要处理BLE设备的数据传输和解析。BLE是一种低功耗的无线通信技术,它通过特定的协议进行数据传输。因此,在进行BLE开发时,需要对BLE数据进行解析,以获取我们所需要的数据内容。在解析数据时,需要根据BLE设备所支持的协议和数据格式来进行相应的处理。 最后,需要将BLE功能集成到QT应用程序中。通过将上述的BLE开发代码与QT的界面设计和交互逻辑相结合,我们可以实现一个完整的BLE应用程序。在应用程序中,可以通过界面交互来搜索和连接BLE设备,并对BLE设备的状态和数据进行展示和控制。 总之,使用QT进行BLE开发需要使用QT的蓝牙API来进行BLE设备的搜索、连接和数据交互,同时需要处理BLE设备的事件和数据传输,最后将BLE功能集成到QT应用程序中实现完整的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值