700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信小程序 - 蓝牙BLE小程序开发

微信小程序 - 蓝牙BLE小程序开发

时间:2021-10-24 12:37:04

相关推荐

微信小程序  - 蓝牙BLE小程序开发

1.前言

最近领导看我比较闲,安排我开发一个蓝牙BLE微信小程序,刚开始接到这个项目时,我第一反应时,"卧槽“”。老子在公司的岗位是做Windows和Android 软件开发的,看我闲,竟然让我去做小程序,我从来没有接触过。后面领导说给你一个星期,看不看能不能完成,实在没有办法,只能硬着头皮去学习小程序。

2.BLE蓝牙相关知识

2.1 经典蓝牙和蓝牙BLE的区别

蓝牙1.0~3.0都是经典蓝牙,有些人一直认为蓝牙4.0就是蓝牙BLE,是错误的。因为4.0是双模的,既包括经典蓝牙又包括低能耗蓝牙。蓝牙BLE相比于经典蓝牙的优点是搜索、连接的速度更快,关键就是BLE(Bluetooth Low Energy)低能耗,缺点呢就是传输的速度慢,传输的数据量也很小,每次只有20个字节。但是蓝牙BLE低能耗,在智能穿戴设备(手环和各种智能硬件)应用越来越广泛。

2.2 相关概念 (参考 通用属性配置文件(GATT)及其服务,特性与属性介绍 )和 (BLE4.0教程二 蓝牙协议之服务与特征值分析)

2.2.1 特性

一个特性至少包含2个属性:一个属性用于声明,一个属性用于存放特性的值。

所有通过GATT服务传输的数据必须映射成一系列的特性,可以把特性中的这些数据看成是一个个捆绑起来的数据,每个特性就是一个自我包容而独立的数据点。 例如,如果几块数据总是一起变化,那么我们可以把它们集中在一个特性里。

2.2.2 服务

一个服务包含一个或多个特性,这些特性是逻辑上相关的集合体。

GATT服务一般包含几块具有相关的功能,比如特定传感器的读取和设置,人机接口的输入输出。组织具有相关的特性到服务中既实用又有效,因为它使得逻辑上和用户数据上的边界变得更加清晰,同时它也有助于不同应用程序间代码的重用。GATT基于蓝牙技术联盟(SIG)官方而设计,SIG建议根据它们的规范设计自己的profile。

2.2.3 UUID

“GATT层”中定义的所有属性都有一个UUID值,UUID是全球唯一的128位的号码,它用来识别不同的特性。

2.3.4 Service和Characteristic (参考 BLE4.0教程二 蓝牙协议之服务与特征值分析)

Service是服务,Characteristic是特征值。蓝牙里面有多个Service,一个Service里面又包括多个Characteristic。

蓝牙4.0是以参数来进行数据传输的,即服务端定好一个参数,客户端可以对这个参数进行读,写,通知等操作,这个东西我们称之为特征值(characteristic,但一个参数不够我们用,比如我们这个特征值是电量的值,另一个特征值是设备读取的温度值。那这时候会有多个特征值,并且我们还会对它们分类,分出来的类我们称之为服务(service)。

一个设备可以有多个服务,每一个服务可以包含多个特征值。为了方便操作,每个特征值都有他的属性,例如长度(size),权限(permission),值(value),描述(descriptor)。

在蓝牙协议里每个蓝牙设备都有多个Service和Characteristic ,同一个Service 有多个Characteristic 。

用什么来区分?就是UUID。每个Service或者Characteristic都有一个 128 bit 的UUID来标识。

3. 微信小程序 - 蓝牙BLE通讯

3.1 需要注意的地方

3.2 使用的API

微信小程序目前有蓝牙 API 共 18 个,其中操作蓝牙适配器的共有 4 个,分别是

wx.openBluetoothAdapter 初始化蓝牙适配器

wx.closeBluetoothAdapter 关闭蓝牙模块

wx.getBluetoothAdapterState 获取本机蓝牙适配器状态

wx.onBluetoothAdapterStateChange 监听蓝牙适配器状态变化事件

其中,扫描和获取周围BLE设备的有4个。

wx.startBluetoothDevicesDiscovery 开始搜寻附近的蓝牙外围设备

wx.stopBluetoothDevicesDiscovery 停止搜寻附近的蓝牙外围设备

wx.getBluetoothDevices 获取所有已发现的蓝牙设备

wx.onBluetoothDeviceFound 监听寻找到新设备的事件

连接BLE设备的2个:

wx.createBLEConnection 连接低功耗蓝牙设备

wx.closeBLEConnection 断开与低功耗蓝牙设备的连接

连接成功后,读写BLE对应特征对象的数据:

wx.getConnectedBluetoothDevices 根据 uuid 获取处于已连接状态的设备

wx.getBLEDeviceServices 获取蓝牙设备所有 service(服务)

wx.getBLEDeviceCharacteristics 获取蓝牙设备所有 characteristic(特征值)

wx.readBLECharacteristicValue 读取低功耗蓝牙设备的特征值的二进制数据值

wx.writeBLECharacteristicValue 向低功耗蓝牙设备特征值中写入二进制数据

wx.notifyBLECharacteristicValueChange 启用低功耗蓝牙设备特征值变化时的 notify 功能

wx.onBLECharacteristicValueChange 监听低功耗蓝牙设备的特征值变化

wx.onBLEConnectionStateChange 监听低功耗蓝牙连接的错误事件

3.3 API 操作流程

微信小程序蓝牙API 操作流程,与Android 类似,但是相比于Android 却简化了很多。

3.3.1.首先是要初始化蓝牙

// 蓝牙相关API/*** 1. 打开蓝牙适配器*/function openBle(callback) {wx.openBluetoothAdapter({success: function (res) {writeLogcat('初始化蓝牙适配器成功' + JSON.stringify(res));callback(0, null);},fail: function (res) {writeLogcat('初始化蓝牙适配器失败, 失败原因: ' + JSON.stringify(res));callback(1, null);}})}

3.3.2. 开启蓝牙搜索,并获取蓝牙设备列表 wx.getBluetoothAdapterState --> wx.onBluetoothAdapterStateChange --> wx.startBluetoothDevicesDiscovery --> wx.onBluetoothDeviceFound --> getBluetoothDevices

/*** 3. 扫描蓝牙设备*/function scanBle(callback) {//开始搜寻附近的蓝牙外围设备wx.startBluetoothDevicesDiscovery({success: function (res) {writeLogcat("成功打开,开始搜寻附近的蓝牙外围设备 ..." + JSON.stringify(res));wx.getBluetoothDevices({success: function (res) {writeLogcat("发现外围蓝牙设备, 设备信息 =" + JSON.stringify(res));callback(0, res);},fail: function (res) {writeLogcat("发送外围蓝牙设备失败, 失败原因 =" + JSON.stringify(res));callback(1, null);}})},fail: function (res) {writeLogcat("扫描失败蓝牙设备 ..." + JSON.stringify(res));callback(1, null);}})}

3.3.3. 选择蓝牙设备获取相应的deviceId(对于需要通讯的蓝牙设备和设备的服务UUID 和特征UUID 需要事先知道,到底与那个BLE设备通讯,不然就算蓝牙设备搜索出来,也不知道)

3.3.4. 连接蓝牙设备 wx.createBLEConnection --> wx.getBLEDeviceService(获取设备的ServiceId)

注意:使用wx.notifyBLECharacteristicValueChange(Object object)对于接收BLE蓝牙设备数据的方式一般的特征有两种(notify 和 indicate ),网上大部分都是使用notify特征的,很少人使用Indicate, 所以需要根据具体使用哪种,从而注册相应特征的通知回调函数,微信的API 也有提到

/*** 4. 连接蓝牙设备 -- 适应 IOS 和 Android* * devices 成员* deviceId 设备MAC地址 * serviceUUIdD 设备服务UUID* writeCharacteristicsUUID 写特征UUID* readCharacteristicsUUID 读特征UUID* indicateCharacteristicsUUID 通知特征UUID*/function connectBle(devices, callback) {//1. 从devices 中获取蓝牙设备mac 地址var deviceId = devices.deviceId;var serviceUUID = null;connectedDeviceId = deviceId;writeLogcat("目标蓝牙设备mac地址 = " + deviceId);wx.createBLEConnection({deviceId: deviceId,success: function (res){writeLogcat('蓝牙设备连接成功');wx.getBLEDeviceServices({deviceId: deviceId,success: function (res) {var deviceService = res.services;writeLogcat('获取蓝牙设备Service信息 = ' + JSON.stringify(res));//连接设备成功,关闭蓝牙发现wx.stopBluetoothDevicesDiscovery();//轮询设备服务UUID var isMatch = false;for (var ik = 0; ik < deviceService.length; ik++) {serviceUUID = deviceService[ik].uuid;writeLogcat("目标蓝牙设备 serviceUUID =" + serviceUUID);//已经匹配上ServiceUUID, 获取相关特征UUIDSif (serviceUUID != devices.serviceUUIdD)continue;else {isMatch = true;break;}}if (isMatch == false) {writeLogcat("未找到目标服务 ...");callback(1, "未找到目标服务 ...");return;}writeLogcat("匹配服务 serviceUUID =" + serviceUUID);//获取蓝牙服务成功ID成功,获取特征值wx.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceUUID,//获取特征值成功success: function (res) {writeLogcat("蓝牙设备特征值信息 = " + JSON.stringify(res));//遍历特征值,找到指定的通知特征,读和写特征值for (var ik = 0; ik < res.characteristics.length; ik++) {var characteristicsUUID = res.characteristics[ik].uuid;writeLogcat("res.characteristics[" + ik + "] uuid = " + characteristicsUUID);writeLogcat("res.characteristics[" + ik + "] properties = " + JSON.stringify(res.characteristics[ik].properties));//保存特征值,如果是通知特征,则需要开启通知服务if (res.characteristics[ik].properties.read == true){globalReadCharacteristicsUUID = characteristicsUUID;writeLogcat("读特征UUID = " + characteristicsUUID);}if (res.characteristics[ik].properties.write == true){globalWriteCharacteristicsUUID = characteristicsUUID;writeLogcat("写特征UUID = " + characteristicsUUID);}//启用低功耗蓝牙设备特征值变化时的 notify 功能if (res.characteristics[ik].properties.indicate == true) {//保存indicate 特征uuidglobalIndicateCharacteristicsUUID = characteristicsUUID;writeLogcat("指示特征UUID = " + characteristicsUUID);wx.notifyBLECharacteristicValueChange({deviceId: deviceId,serviceId: serviceUUID,characteristicId: characteristicsUUID,state: true, //开启通知功能success: function (res) {writeLogcat("启用低功耗蓝牙设备特征值变化时的 notify 功能成功," + JSON.stringify(res));//注册通知特征,回调函数wx.onBLECharacteristicValueChange(receiveBleData);callback(0, res);},fail: function (res) {writeLogcat("启用低功耗蓝牙设备特征值变化时的功能失败,失败原因 = " + JSON.stringify(res));callback(1, res);},});}}},fail: function (res) {writeLogcat('获取设备特征值失败, 失败原因 =' + JSON.stringify(res));callback(1, res);},});},fail: function (res) {writeLogcat('获取设备服务失败,失败原因 = ' + JSON.stringify(res));callback(1, res);}});},fail: function (res) {writeLogcat('蓝牙设备连接失败,请稍后重试,失败原因 = ' + JSON.stringify(res));callback(1, res);}});}

3.3.5 关闭蓝牙连接

/*** 5. 断开与蓝牙设备连接*/function disconnectBle(callback) {wx.closeBLEConnection({deviceId:connectedDeviceId,success: function (res){writeLogcat('断开蓝牙设备成功:' + JSON.stringify(res));callback(0, res);},fail: function (res) {writeLogcat('断开蓝牙设备失败:' + JSON.stringify(res));callback(1, res);}})}

3.3.6 ble 发送数据

/*** 发送20个字节*/function writeBle(devices, cmd, onSuccessCallback, onFailCallback){writeLogcat("发送第" + globalIndex + "包 = " + cmd);//需要发送的数据var packetBuffer = stringToArrayBuffer(cmd);wx.writeBLECharacteristicValue({deviceId: devices.deviceId,serviceId: devices.serviceUUId,characteristicId: devices.writeCharacteristicsUUID,value: packetBuffer,success: function (res){//发送成功writeLogcat("蓝牙发送成功");onSuccessCallback();},fail: function (res) {writeLogcat("蓝牙发送失败,失败原因: " + JSON.stringify(res));//onFailCallback();},});

3.3.6 读取串口发送的数据

wx.getBLEDeviceCharacteristics --> success:wx.notifyBLECharacteristicValueChange --> success:wx.readBLECharacteristicValue --> wx.onBLECharacteristicValueChange

/*** 2. 接收数据处理 -- 打开定时器,200ms 超时表示接收完成*/function receiveBleData(res){var dataStr = arrayBufferToHexString(res.value).toUpperCase();writeLogcat("接收长度 = " + (dataStr.length / 2) + ", 数据 = " + dataStr);globalReceiveBuffer += dataStr;globalPacketTotalLength += (dataStr.length / 2);writeLogcat("当前接收总长度 = " + globalPacketTotalLength);//收到包头,计算微信协议数据包总长度if (dataStr.substr(0, 2) == "FE" && globalIsCalwxProtocolLength == false){globalIsCalwxProtocolLength = true;//计算微信协议数据总长度globalwxPacketLength = hex2StringToInt(dataStr.substr(4, 4));writeLogcat("微信协议数据总长度 = " + globalwxPacketLength);}else{//判断是否接收完整一包的微信协议包,是则调用回调处理//接收长度大于等于微信协议长度if (globalPacketTotalLength >= globalwxPacketLength && globalIsCalwxProtocolLength == true){//处理数据writeLogcat("接收完整一包完成,开始处理数据");writeLogcat("完整一包数据 = " + globalReceiveBuffer);sleep(100);processwxProtocol(globalReceiveBuffer);// wx.onBLECharacteristicValueChange(receiveBleData);//等待接收下一包globalReceiveBuffer = "";globalPacketTotalLength = 0;globalwxPacketLength = 0;globalIsCalwxProtocolLength = false;}else{globalReceiveBuffer = "";globalPacketTotalLength = 0;globalwxPacketLength = 0;globalIsCalwxProtocolLength = false;}}}

3.3.7 关闭蓝牙适配器

/**** 2. 关闭蓝牙适配器*/function closeBle(callback) {wx.closeBluetoothAdapter({success: function (res) {writeLogcat("关闭蓝牙适配器成功," + JSON.stringify(res));callback(0, null);},fail: function (res) {writeLogcat("关闭蓝牙适配器失败, 失败原因: " + JSON.stringify(res));callback(1, null);}})}

问题总结:

1. android手机使用小程序的BLE模块,广播中的deviceId表示设备的mac信息,ios系统则是手机mac和设备mac加密产生的uuid值!连接设备也如此:安卓直接使用mac进行连接操作;但ios使用广播中读取到的UUID进行连接。

简而言之,全是扫描到设备后的deviceId信息。

2. Android手机使用小程序操作BLE设备,连接成功后可以直接进行特征数据的获取;但ios直接调用时,会出现10004的报错 官方文档报错信息连接。

如何解决ios手机使用小程序BLE报错问题。

只需要在连接成功和读设备特征数据之间,进行一项开启通信服务操作即可,按照java android开发ble规范来说,连接成功后是需要优先开启服务的,所以android和ios都统一开启服务!!

3.ISO 系统:

1.1 我使用自己的手机(型号是iPhone XS Max 系统版本: ios13.1 )测试时,发现怎么初始化蓝牙适配器总是失败,后来怀疑是不是系统太新了,小程序底层没有适配,于是迫不得已我当天晚上在宿舍刷机(o(╥﹏╥)o),刷回ios12.4.1 测试发现可以初始化蓝牙适配器,后来第二天早上在上班路上,看最先ios13 新闻,突然间想起来在ios13 新增蓝牙权限,是不是权限问题呢?于是,我又把手机升级到ios13.0 测试发现真的是权限问题。o(╥﹏╥)o 白白刷了两次手机。

4. 蓝牙BLE 最大支持20个字节发送,因此,超过20个字节需要分包发送。

参考文章

通用属性配置文件(GATT)及其服务,特性与属性介绍

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。