美文网首页
uniapp实现BLE蓝牙连接多个电子秤设备

uniapp实现BLE蓝牙连接多个电子秤设备

作者: 一页莲子 | 来源:发表于2022-12-03 15:50 被阅读0次

前言:

前段时间 在公司开发一款APP 其中有一个需求对接某厂蓝牙电子秤(类似地磅秤、多蓝牙),第一次对接这种 开发中遇到好多问题、比如将plus.bluetooth.writeBLECharacteristicValue 指定指令字符串转二进制 ArrayBuffer、uni.notifyBLECharacteristicValueChange蓝牙返回指令值十六进制转换字符串等。需要的小伙伴 可以点个关注哈!

整理需求及应用场景:

其实我们做开发的 只要业务逻辑、需求理解等清楚了 剩下的就是码code的事情了、主要就是按照以下几步 基本这个需求就能完成了。

JS部分

    data() {
            return {
                a:'',
                va:'',
                b:'',
                vb:'',
                lastValue:'', //最终棒棒称重量
                temdeviceIds:[], //选择已连接设备 临时
                deviceIds:[], //选择已连接设备
                arrbuffer: undefined,
                Loading: false,
                bluetoothList: []
            };
        },
        onLoad() {
            this.InitBle()
        },
        onUnload() {
            if (this.timer1) {
                clearTimeout(this.timer1);
                this.timer1 = null;
            }
            if (this.timer2) {
                clearTimeout(this.timer2);
                this.timer2 = null;
            }
            if (this.timer3) {
                clearInterval(this.timer3);
                this.timer3 = null;
            }
        },

1.首先初始化蓝牙

InitBle() {
                let _this = this
                uni.openBluetoothAdapter({ //初始化蓝牙模块
                    success(res) {
                        console.log('初始化蓝牙', res)
                        _this.SearchBle(); //2.0
                    },
                    fail(err) {
                        uni.showToast({
                            title: '请检查是否已开启蓝牙',
                            icon: 'none',
                            duration: 1500
                        })
                    }
                })
            },
2.搜索蓝牙设备
    GetBleList() {
                var _this = this;
                uni.getBluetoothDevices({
                    success: function(res) {
                        var bluetoothArr = res.devices.filter(function(obj) {
                            return obj.name.indexOf('LEAP')!=-1 //此处是过滤自己想要连接的蓝牙设备
                        })
                        _this.bluetoothList = bluetoothArr  //将蓝牙列表展示在页面中 
                    },
                    fail: function() {
                        console.log("搜索蓝牙设备失败");
                        uni.showToast({
                            title: '搜索蓝牙设备失败或附件暂无开启的蓝牙设备',
                            icon: 'none',
                            duration: 2000
                        })
                    },
                    complete: function() {
                        uni.hideLoading()
                        _this.Loading = false
                        _this.StopSearchBle() //不管是否有搜索到蓝牙设备 都要在complete中关闭蓝牙 优化性能
                    }
                })
            },
3.停止蓝牙搜索
StopSearchBle() {
                uni.stopBluetoothDevicesDiscovery({
                    success(res) {
                        console.log('停止搜索蓝牙', res)
                    }
                })
            },
4.找到蓝牙设备后 页面点击选择某个蓝牙设备(此需求是可以连接多个蓝牙设备)
goConnectBle(e, index) {
                console.log('开始连接蓝牙', e, index)
                this.Loading = true
                let item = {
                  deviceId: e.deviceId,
                  name: e.name,
                };
                this.temdeviceIds.push(item); //临时已连接的蓝牙设备
                this.deviceIds = this.uniqueFunc(this.temdeviceIds,'deviceId') //去重后的蓝牙设备
                // 将点击蓝牙设备 存放数组遍历 用户设备可链接多蓝牙
                uni.showLoading({
                    title:'正在连接中...'
                })
//此处为重点 蓝牙连接  根据某一id连接设备,4.0
                this.deviceIds.map(item=>{
                    this.ConnectBle(item)
                })
            },

5.去重方法
uniqueFunc(arr, uniId){
              const res = new Map();
              return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
            }
6.选择连接蓝牙设备后相关特征信息
        ConnectBle(item) {
                var _this = this;
                uni.createBLEConnection({
                    deviceId: item.deviceId, //设备id
                    success: (res) => {
                        uni.hideLoading()
                        _this.NoticeConnection(); //连接成功后,开始监听异常
                        _this.timer2 = setTimeout(() => { //加个延迟、目的是为了确保连接成功后,再获取服务列表--可以显示正在连接效果
                            _this.Loading = false
                            _this.timer3 = setInterval(()=>{ 
                            _this.GetServiceId(item.deviceId); //5.0 获取蓝牙uuid 会存在多个 具体根据某厂商文档告知
                                _this.writeTest(item) //写入指令 告知电子秤设备(一般某厂商在开发文档、说明文档告知)
                            },10000)  //此处为模拟轮询 第一次会出现获取不到蓝牙特性信息、将值调整小一点即可获取
                            uni.showToast({
                                title: '连接成功',
                                icon: 'success',
                                duration: 800
                            })
                        }, 3000)
                    },
                    fail: function(err) {
                        if (err.errMsg == 'createBLEConnection:fail already connect') {
                            _this.Loading = false
                            uni.showToast({
                                title: '已有蓝牙连接',
                                duration: 1200
                            })
                        } else {
                            uni.showToast({
                                title: err.errMsg,
                                duration: 1200
                            })
                        }
                    },
                    complete: function() {
                        // console.log('蓝牙连接完成')
                    }
                })
            },
7.连接成功后,开始监听异常
NoticeConnection() {
                var _this = this;
                uni.onBLEConnectionStateChange((res) => {
                    console.log('开始监听蓝牙状态', res)
                    if (!res.connected) {
                        uni.showModal({
                            title: '提示',
                            content: '蓝牙已断开,请重新搜索重连!',
                            success(res) {}
                        })
                    }
                })
            },
8.获取蓝牙(5.0)设备的服务uuid(服务uuid可能有多个)
GetServiceId(deviceId) {
                console.log('连接的蓝牙设备deviceId====', deviceId)
                var _this = this
                uni.getBLEDeviceServices({
                    deviceId,
                    success(res) {
                        _this.serviceid_list = res.services //蓝牙服务列表放在data里面只是备用
                        _this.serviceId = 'xxxxxxxxxxxxxxxxx' //这是用来监听蓝牙下发和接收的服务uuid 一般厂商提供说明文档有提到
                        _this.GetCharacteIdNotify(_this.serviceId, 
                            deviceId) //6.0  获取第2个服务uuid的特征值 (关于获取第几个uuid服务,看蓝牙方面提供的协议
                    }
                })
            },
9.根据服务uuid获取蓝牙特征值,开始监听写入和接收
    GetCharacteIdNotify(serviceId, deviceId) {
                let _this = this
                uni.getBLEDeviceCharacteristics({
                    deviceId,
                    serviceId, 
                    success(res) {
                        console.log('获取蓝牙特征值', res.characteristics)
                        _this.arrbuffer = res.characteristics
                        _this.writeId = res.characteristics[1].uuid //写入 id  此处根据实际情况写
                        _this.notifyId = res.characteristics[0].uuid //接收id 此处根据实际情况写
                    }
                })
            },
10.写入指令(按某厂商说明文档 给出指定指令)
writeTest(item) {
    this.BleWrite('$xxxx#', item.deviceId)
}
11.向蓝牙写入数据 传递电子秤设备信息
    BleWrite(instruction, deviceId) {
                // 向蓝牙设备发送一个0x00的16进制数据
                let _this = this
                let serviceId = _this.serviceId
                let characteristicId = _this.writeId
                let msg = instruction 
                const buffer = new ArrayBuffer(msg.length)
                const dataView = new DataView(buffer)
                for (var i = 0; i < msg.length; i++) {
                    dataView.setUint8(i, msg.charAt(i).charCodeAt())
                }
                plus.bluetooth.writeBLECharacteristicValue({
                    deviceId, // 蓝牙设备 deviceId
                    serviceId, // 蓝牙服务uuid,即第二个uuid
                    characteristicId, // 蓝牙特征值的 (即 writeId)
                    value: buffer, // 这里的value是ArrayBuffer类型
                    success(res) {
                        _this.startNoticeBle(_this.notifyId,deviceId) //7.0,开始侦听数据
                    },
                    fail(err) {
                        console.log('写入数据失败', err)
                        uni.showToast({
                            icon: "none",
                            title: "请确保您的手机已连接设备",
                            duration: 3000
                        })
                    }
                })
            },
12.写入指令成功后,开始侦听蓝牙发送数据 处理接收
startNoticeBle(notifyId,deviceId) {
                let _this = this
                uni.notifyBLECharacteristicValueChange({
                    state: true, // 启用 notify 功能
                    deviceId: deviceId,
                    serviceId: _this.serviceId,
                    characteristicId: notifyId,
                    success(res) {
                        setTimeout(function() {
                            uni.onBLECharacteristicValueChange((res) => {
                                _this.hexCharCodeToStr(_this.ab2hex(res.value)) // hexCharCodeToStr为蓝牙返回的是十六进制的值 此处要将十六进制值转换成字符串   ab2hex 为ArrayBuffer转16进度字符
                            })
                        }, 5) //延迟是为异步更好拿出数据
                    },
                    fail: function(err) {
                        console.log('开启监听失败', err)
                    }
                })
            },
13.ArrayBuffer转16进度字符串
    ab2hex(buffer) {
                const hexArr = Array.prototype.map.call(
                    new Uint8Array(buffer),
                    function(bit) {
                        return ('00' + bit.toString(16)).slice(-2)
                    }
                )
                return hexArr.join('')
            },
14.将十六进制转换字符串
    hexCharCodeToStr(hexCharCodeStr) {  
                const _this = this
                _this.lastValue = ''
                        var trimedStr = hexCharCodeStr.trim();  
                        var reslutr = ''
                        var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;  
                        var len = rawStr.length;  
                        if (len % 2 !== 0) {  
                            alert("存在非法字符!");  
                            return "";  
                        }   
                        var curCharCode;  
                        var resultStr = [];  
                        for (var i = 0; i < len; i = i + 2) {  
                            curCharCode = parseInt(rawStr.substr(i, 2), 16);  
                            resultStr.push(String.fromCharCode(curCharCode));  
                        }  
//设备的特征值 这里值的是设备号 和蓝牙没有关系
                if(resultStr.join("").replace(',', '').indexOf('W')!=-1){
                        if(_this.a=='' || _this.a == resultStr.join("").replace(',', '').substring(0, 5)){
                            _this.a = resultStr.join("").replace(',', '').substring(0, 5)
                            _this.va = resultStr.join("").replace(',', '').substring(6, resultStr.length - 2)
                        }else if(_this.b=='' || _this.b== resultStr.join("").replace(',', '').substring(0, 5)){
                            _this.b = resultStr.join("").replace(',', '').substring(0, 5)
                            _this.vb = resultStr.join("").replace(',', '').substring(6, resultStr.length - 2)
                        }
                } 
                        console.log('电子秤称完整信息',resultStr.join("").replace(',',''))
                        _this.lastValue =Number(_this.va) + Number(_this.vb)
}
15.设备无法连接 需要重新获取
请调用 第一个方法 this.InitBle()

html部分

<template>
    <view class="box">
        <view class="content" v-if="Loading">
            <view class="content_b" />
        </view>
        <view style="height: 100%;" v-else>
            <view class="content" v-if="bluetoothList.length>0">
            <view class="" v-if="bluetoothList && bluetoothList.lenght!=0">
                 <view class="ffass" v-for="(item,index) in bluetoothList" :key="index">
                    <view class="trycsd">
                        <view class="nmjer">
                            <image src="/static/image/xxx.png" mode="" class="mjqwex"></image>
                        </view>
                        <text>{{item.name}}</text>
                    </view>
                    <text class="fdstrd" @click="goConnectBle(item,index)">点击链接</text>
                 </view>
            </view>
                <view class="" v-show="lastValue">
                    当前重量:{{lastValue}} +kg  
                </view>  
            </view>
            <view class="content" v-else style="margin: 300rpx auto;margin-bottom: 0;">
                <view class="content_t">
                    <view class="common_txt" style="color: #000">
                        未发现附近的蓝牙设备
                    </view>
                    <view style="margin-bottom: 50rpx;" size="default" shape="circle" :hairLine="true"
                        class="common_txt" @click="ReSearchBle()">
                        重新扫描
                    </view>
                </view>
                <view class="content_b" />
            </view>
        </view>
    </view>
</template>

css部分

<style lang="scss" scoped>
    .content {
        display: flex;
        flex: 1;
        height: 100%;
        flex-direction: column;
        .bluetooth_item {
            border-bottom: 1rpx solid #ccc;
            line-height: 100rpx;
            padding: 0 50rpx;
            display: flex;
            justify-content: space-between;
        }
    }
    .content_t {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        align-items: center;

        .txt {
            color: red;
            margin: 40rpx 0rpx 120rpx;
            font-size: 34rpx;
        }
    }
    .content_b {
        flex: 1;
    }
    .common_txt {
        color: indianred;
        font-size: 34rpx;
    }
    .ffass{
        width: 698rpx;
        height: 180rpx;
        background: #FFFFFF;
        border-radius: 10rpx;
        overflow: hidden;
        margin: 30rpx auto;
        display: flex;
        justify-content: space-between;
        align-items: center;
        .nmjer{
            width: 152rpx;
            height: 152rpx;
            background: #F9F9F9;
            border-radius: 10rpx;
            display: flex;
            justify-content: center;
            align-items: center;
            margin-right: 30rpx;
            margin-left: 14rpx;
            .mjqwex{
                width: 85rpx;
                height: 85rpx;
            }
        }
        .trycsd{
            display: flex;
            align-items: center;
        }
        .fdstrd{
            display: inline-block;
            height: 68rpx;
            width: 196rpx;
            background: #FFFFFF;
            border-radius: 5rpx;
            color: #5A9CFE;
            font-size: 32rpx;
            border: 1px solid #5A9CFE;
            margin-right: 20rpx;
            line-height: 68rpx;
            text-align: center;
        }
    }
</style>

觉得还可以的话,麻烦给作者点个关注咯,您的关注就是动力!

相关文章

网友评论

      本文标题:uniapp实现BLE蓝牙连接多个电子秤设备

      本文链接:https://www.haomeiwen.com/subject/zqnpfdtx.html