微信小程序实现蓝牙连接通讯

由于最近的项目在做小程序蓝牙通讯这块的内容,所以将实现的过程在这简单的记录下。

1、首先要初始化蓝牙-检查蓝牙适配器是否打开

 async initBluetooth(): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            const _this = this
            if (BluetoothController.adapterOpend) {
                console.log("蓝牙适配器已打开")
                resolve(true)
                return
            }
            wx.openBluetoothAdapter({
                success(res) {
                    BluetoothController.adapterOpend = true
                    console.log("=====*****蓝牙适配器已打开")
                    resolve(true)
                },
                fail(error) { //用来判断蓝牙是否已打开
                    reject(error)
                    BluetoothController.adapterOpend = false
                    console.log("=====*****蓝牙适初始化失败", error)
                }
            })
        })
    }

//使用案例
initBluetooth().then()

2、开始搜寻附近的蓝牙外围设备

 /**
     * @param options 
     * options.keywords  蓝牙名称筛选关键字
     * options.deviceid  可选参数,蓝牙设备id,连接用
     */
    async searchAroundBLE(options: any): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            const _this = this
            if (_this.startDiscovery) {
                console.log("已开启蓝牙扫描,勿重复开启")
                resolve(true)
                return
            }
            _this.startDiscovery = true
            wx.startBluetoothDevicesDiscovery({
                allowDuplicatesKey: true,
                services: options.services,
                success(res) {
                    console.log('搜索成功', res);
                    resolve(true)

                },
                fail(error) {
                    reject(error)
                    _this.startDiscovery = false
                },
            })
        })

    }


//使用案例
 searchAroundBLE({ 'keywords': [''], services: [] }).then()

3、监听搜索到的设备

 /**
     * @param options 
     * options.keywords  蓝牙名称筛选关键字
     * options.deviceid  可选参数,蓝牙设备id,连接用
     */
    async onBluetoothDeviceFound(options: any): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            let _this = this
            let { keywords } = options
            // 超时自动结束
            _this.findTimer = setTimeout(() => {
                clearTimeout(_this.findTimer)
                if (!_this.connectStatus) {
                   reject({ 
                        success: false
                    })
                    console.log('蓝牙扫描超时,自动关闭任务')
                }
            }, 3000); //时间根据自己的需求定
            let arr: any = []
            wx.onBluetoothDeviceFound(res => {
                let devices = res.devices;
                devices.forEach((device) => {
                    if (!device.name && !device.localName) {
                        return
                    }
                    // 获取设备MAC地址,并根据关键字过滤
                    let systemInfo = wx.getSystemInfoSync()
                    let iosDevice = systemInfo.system.toLowerCase().indexOf("ios") > -1;
                    let deviceMac = iosDevice ? uuid2Mac(device.advertisData) : device.deviceId
                    // keywords
                    if (keywords && keywords.length > 0) {
                        let key = keywords[0]
                        if (device.name.indexOf(key) >= 0) {
                            arr.push({
                                ...device,
                                deviceMac
                            })
                        }
                        if (arr.length) {
                            let foundDevices = arr
                            _this.deviceList = foundDevices
                            resolve({
                                data: arr,
                                success: true
                            })
                        }
                    }
                })
            })

        })

    }


/**
 * 统一安卓与IOS端deviceId展示
 * @param advertisData 
 * 在安卓设备中,获取到的 deviceId 为设备 MAC 地址,iOS 上则为设备 uuid,
 * 因此为了展示一致需要将ios的展示进行输入(当然IOS的连接还是得用获取到的uuid)
 */
function uuid2Mac(advertisData: any) {
    if (advertisData) {
        let mac = Array.prototype.map
            .call(new Uint8Array(bf), (x) => ("00" + x.toString(16)).slice(-2))
            .join(":");
        mac = mac.toUpperCase();
        return mac;
    }
}


使用案例: onBluetoothDeviceFound({ 'keywords': [''] }).then()  //keywords根据自己的需求去定,

4、处理蓝牙连接(搜索到设备开始蓝牙链接)

/**
     * @param {string} options.deviceId 蓝牙设备id,连接用
     */
    async createBLEConnection(options: any): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            let { deviceId } = options,_this = this
            _this.deviceId = deviceId
            if (_this.connectStatus) {
                wx.closeBLEConnection({
                    deviceId
                })
            }
            let timeout = 3000 //根据自己需求去定
            console.log('开始连接蓝牙--', deviceId)
            _this.stopBLEDevicesTask()
            wx.createBLEConnection({
                deviceId,
                timeout,
                success(res) {
                    console.log('蓝牙连接成功-----', deviceId)
                    _this.connectStatus = true

                    resolve(true)
                },
                fail() {
                    _this.connectStatus = false
                    reject(false)
                }
            })
        })
    }


使用案例: createBLEConnection({ deviceId: tmp[0].deviceId }).then()

5、连接成功后,要获取蓝牙的所有服务 进而根据项目需求的服务 去获取对应的特征 来进行读写操作

 /**
     * @param deviceId  蓝牙设备Id,来自createBLEConnection调用
     */
    async getBLEDeviceServices(deviceId: any): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            let _this = this
            wx.getBLEDeviceServices({
                deviceId,
                success(res) {
                    /**
                     * 16 位 UUID 从对接文档中获取(注意都是0000开头,接着的4位数字为16进制的uuid,所有服务只有4位uuid不一样)
                注意有多个服务,不同服务的操作不一样,单个服务只能执行单个操作,所以这里需要建立多个连接
                     */
                    for (let i = 0; i < res.services.length; i++) {
                        // 注意uuid的大小写
                        if (
                            res.services[i].isPrimary &&
                            res.services[i].uuid == "0000D0FF-0000-1000-8000-008cbhschs" //设备id,根据自己的项目去走
                        ) {
                            // _this.getBLEDeviceCharacteristics(res.services[i].uuid);
                            resolve({
                                data: res.services[i].uuid,
                                sucess: true
                            })
                            return;
                        }
                    }
                },
                fail: (res) => {
                    reject({
                        sucess: false,
                        data: res.errMsg
                    })
                    console.log("服务获取失败------------->", res.errMsg);
                },
            });
        })
    }


  async getBLEDeviceCharacteristics(serviceId: any): Promise<void> {
        return new Promise((resolve: any, reject: any) => {
            let _this = this
            wx.getBLEDeviceCharacteristics({
                deviceId: _this.deviceId,  //设备id根据自己项目的去赋值
                serviceId,  //服务id
                success: (res) => {
                    // 设备特征列表
                    let characteristics = res.characteristics;
                    for (let i = 0; i < characteristics.length; i++) {
                        let item = characteristics[i];
                        if (item.properties.write) {
                            this.serviceId = serviceId
                            this.characteristicId = item.uuid
                        }
                        if (item.properties.read) {
                            wx.readBLECharacteristicValue({
                                deviceId: _this.deviceId,
                                serviceId,
                                characteristicId: item.uuid
                            });
                        }
                        if (item.properties.write) {
                            // resolve({
                            //     data: 1,
                            //     sucess: true
                            // })
                        }
                        if (item.properties.notify || item.properties.indicate) {
                           /* 启用蓝牙低功耗设备特征值变化时的 notify 功能,订阅特征。注                        意:必须设备的特征支持 notify 或者 indicate 才可以成功调用。
另外,必须先启用 wx.notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件*/

                            wx.notifyBLECharacteristicValueChange({
                                deviceId: _this.deviceId,
                                serviceId,
                                characteristicId: item.uuid,
                                state: true,
                            });
                            resolve({
                                data: item.properties,
                                sucess: true
                            })
                        }
                    }
                },
                fail(error: any) {
                    reject({
                        sucess: false,
                        data: error
                    })
                }
            });
        })
    }

使用案例: let { data } = await getBLEDeviceServices(tmp[0].deviceId)  //data就是所有服务内容
 if (data) {
        // 2、获取蓝牙低功耗设备某个服务中所有特征 (characteristic)
        let ble_chart = await getBLEDeviceCharacteristics(data)
        if (ble_chart.sucess) {
              let item = ble_chart.data
              // 该特征是否支持 write 操作
              if (item.write) {
                   // resolve(true)
                   this.handleWriteSucess();  //处理写操作
              }
              // 该特征是否支持 notify ,indicate操作 ,开启监听订阅特征消息
              if (item.notify || item.indicate) {
                   this.watchBleData()//监听蓝牙数据
              }
        }
}

6、读写成功后开始根据蓝牙协议进行操作(蓝牙协议有设备方提供)

handleWriteSucess()  //写成功后的操作
watchBleData() {
    wx.onBLECharacteristicValueChange(async (res) => { //监听蓝牙数据变化
         let resHex = ab2hex(res.value).toLocaleUpperCase() //包数据, 根据蓝牙协议去进行处理
         let { data } = writeBLECharacteristicValue('对应指令', '脚电极')
    })
}

/**
 * ArrayBuffer转16进度字符串
 * @param buffer 
 */
// ArrayBuffer转16进度字符串
ab2hex(buffer: any) {
    var hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
        return ("00" + bit.toString(16)).slice(-2);
    });
    return hexArr.join("");
}

 7、处理蓝牙写指令

 /**
   * 4. 发送蓝牙指令。蓝牙指令超出20字符时需要截断多次发送
   * @param {string} cmdStr 蓝牙指令
   * @param {string} cmdName 蓝牙指令名称——可选用于打印调试
   */
    async writeBLECharacteristicValue(cmdStr: any, cmdName: string): Promise<void> {
        // // console.log("发送蓝牙指令------------》", cmdStr, cmdName);
        return new Promise((resolve: any, reject: any) => {
            let _this = this
            let data = cmdStr.split(',')
            let buffer = new ArrayBuffer(data.length);
            let dataViewLast = new DataView(buffer);
            for (let i = 0; i < data.length; i++) {
                dataViewLast.setUint8(i, data[i]);
            }
            let param: any = {
                deviceId: _this.deviceId,
                serviceId: _this.serviceId,
                characteristicId: _this.characteristicId,  //在获取特性那有
                value: dataViewLast.buffer,
            };
            console.log("param", param)
            wx.writeBLECharacteristicValue({
                ...param,
                success: function () {
                    console.log("发送指令成功", cmdName);
                    resolve({
                        data: {
                            cmdName,
                            sucess: true
                        }
                    })
                },
                fail: function (error: any) {
                    reject({
                        data: {
                            data: error,
                            sucess: true
                        }
                    })
                },
            })
        })

    }

注意点:

在判断蓝牙是否打开之前,还要先判断下手机上位置是否打开

let locationEnabled = wx.getSystemInfoSync().locationEnabled

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/569429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【树莓派学习】开发环境配置

【树莓派学习】开发环境配置 ​ Raspberry Pi OS作为基于Linux的系统&#xff0c;其默认网络配置在国内的网络环境下容易出现访问慢甚至无法连接等问题&#xff0c;不便于我们的学习&#xff0c;同时&#xff0c;树莓派上C/C的使用需要单独安装WiringPi。本文主要介绍如何更改…

蓄能勃发,酷开科技携酷开系统“软硬结合”提升大屏实力

智慧大屏以全新媒体形态之姿在过去几年快速增长&#xff0c;截至去年上半年&#xff0c;国内联网电视总量覆盖达5.26亿&#xff0c;其中智能电视终端活跃量达3.22亿&#xff0c;在PC、Mobile流量增长已显疲态的背景下&#xff0c;大屏的高速发展意味着一个新的赛道的崛起&#…

使用甘特图来做时间管理

在这个追求效率的时代,掌握高超的时间管理技能几乎等同于掌控了成功。事实上,时间就是金钱,更是稀缺资源。那么,如何高效地规划和利用时间呢?甘特图应该是您的必备武器之一。 甘特图(Gantt chart)名字虽然有些陌生,但它的使用范围确实广泛。无论是全职妈妈安排家务,还是上市公…

蓝桥杯-网络安全-练习题-crypto-rsa

共模攻击 直接脚本即可 import libnum import gmpy2import random random.seed(123456)e1 random.randint(100000000, 999999999) print(e1) e2 65537 n 7265521127830448713067411832186939510560957540642195787738901620268897564963900603849624938868472135068795683…

低代码技术的全面应用:加速创新、降低成本

引言 在当今数字化转型的时代&#xff0c;企业和组织面临着不断增长的应用程序需求&#xff0c;以支持其业务运营和创新。然而&#xff0c;传统的软件开发方法通常需要大量的时间、资源和专业技能&#xff0c;限制了企业快速响应市场变化和业务需求的能力。在这样的背景下&…

VS窗口固定尺寸的方法

Dialog每次都要找窗口尺寸固定的设置&#xff0c;因此在这个地方做个笔记 下次就好检索了。年级大了 脑子不够用了。

vben admin Table 实现表格列宽自由拖拽

更改BasicTable.vue文件 Table添加 resize-column“resizeColumn” 添加并 return resizeColumn const resizeColumn (w, col) > { setCacheColumnsByField(col.dataIndex, { width: w }); }; 在column中添加 resizable: true,

jackson.dataformat.xml 反序列化 对象中包含泛型

重点&#xff1a; JacksonXmlProperty localName 指定本地名称 JacksonXmlRootElement localName 指定root的根路径的名称&#xff0c;默认值为类名 JsonIgnoreProperties(ignoreUnknown true) 这个注解写在类上&#xff0c;用来忽略在xml中有的属性但是在类中没有的情况 Jack…

书籍发售:七个阶段,让你详细了解“有书共读”的完整发售流程

有书共读发售流程 你要在本子上画一个流程或者是导图上。 首先整个过程分成7个阶段: 第1个:预告阶段, 第2个:售书阶段, 第3个:发货阶段, 第4个:共读阶段, 第5个:发售阶段, 第6个:售卖周期, 第7个:发售结束, 一共7个阶段,最重要的是前5个阶段,第6和7个…

边缘计算是什么?

一、边缘计算是什么&#xff1f; 边缘计算是一种分布式计算范式&#xff0c;它将计算任务和数据存储从中心化的云端推向网络的边缘&#xff0c;即设备或终端&#xff0c;以提高响应速度和降低网络带宽需求。在边缘计算中&#xff0c;数据在源头附近进行处理和分析&#x…

Hadoop格式化namenode出错

​ 我们在对Hadoop进行格式化时 很有可能会出现以下错误 输入命令&#xff1a;hadoop namenode -format 报错信息&#xff1a;-bash&#xff1a;hadoop&#xff1a;command not found 我们总结的最主要原因有三个 Hadoop的环境变量是否配置 配置以后是否使其生效 vim /e…

HYBBS表白墙爆款源码!轻松搭建表白墙网站,更可一键封装成APP,让爱传递无界限

PHP表白墙网站源码&#xff0c;适用于校园内或校区间使用&#xff0c;同时支持封装成APP。告别使用QQ空间的表白墙。 简单安装&#xff0c;只需PHP版本5.6以上即可。 通过上传程序进行安装&#xff0c;并设置账号密码&#xff0c;登录后台后切换模板&#xff0c;适配手机和PC…

其他代码题

1.阶乘累加 2.回文数 3.字典查询 4.“结构体”的应用 5.链表

凌恩病原微生物检测系统上线啦,助力环境病原微生物检测

病原微生物是指能够引起人类或动物疾病的微生物&#xff0c;包括病毒、细菌、真菌、衣原体和支原体等。病原微生物可以通过空气、体液等介质传播&#xff0c;危害人体健康&#xff0c;造成财产损失。因此&#xff0c;快速、准确地检测病原微生物对于疫情防控和保障人民生命健康…

北京筑龙当选中招协第二届招标采购数字化专业委员会执行主任单位

4月18-19日&#xff0c;中国招标投标协会&#xff08;以下简称中招协&#xff09;2024年年会在宁波召开&#xff0c;北京筑龙作为中招协理事会员单位受邀出席会议。会议期间举行了“电子招标采购专业委员会换届会议暨第二届第一次工作会议”&#xff0c;北京筑龙当选第二届招标…

Leetcode 第 393 场周赛题解

Leetcode 第 393 场周赛题解 Leetcode 第 393 场周赛题解题目1&#xff1a;3114. 替换字符可以得到的最晚时间思路代码复杂度分析 题目2&#xff1a;3115. 质数的最大距离思路代码复杂度分析 题目3&#xff1a;3116. 单面值组合的第 K 小金额思路代码复杂度分析 题目4&#xff…

探索人工智能的边界:GPT 4.0与文心一言 4.0免费使用体验全揭秘!

探索人工智能的边界:GPT与文心一言免费试用体验全揭秘! 前言免费使用文心一言4.0的方法官方入口进入存在的问题免费使用文心一言4.0的方法免费使用GPT4.0的方法官方入口进入存在的问题免费使用GPT4.0的方法前言 未来已来,人工智能已经可以帮助人们完成许多工作了,不少工作…

【FX110网】股市、汇市一年有多少个交易日?

事实上&#xff0c;作为交易者&#xff0c;重要的是要了解并非每天都是交易日。虽然金融市场在大多数工作日开放交易&#xff0c;但在某些特定情况下无法进行交易。这些非交易日可能因各种原因而发生&#xff0c;包括节假日、周末和市场休市。 通过随时了解假期、交易时间表和市…

CSS3:border-image

<!DOCTYPE html> <html><head><meta charset"utf-8"> </head><body><p>原始图片</p><img src"./images/border1.png" alt""><p>一、</p><p>border: 27px solid transp…

qt5-入门-自定义委托-可编辑的TableModel与信号接收

参考&#xff1a; C GUI Programming with Qt 4, Second Edition 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt5.12 上一篇&#xff1a; qt5-入门-自定义委托-简单例子_qt 委托-CSDN博客 https://blog.csdn.net/pxy7896/article/details/137234839 本篇重…
最新文章