uni-app 小程序蓝牙配网
前言:
本文介绍了uniapp 的蓝牙调用,如搜索蓝牙,连接蓝牙设备
蓝牙接口API

一、搜索蓝牙页面代码
HTML
<view class="container"> <scroll-view scroll-y :style="'width:690rpx;height:' + list_height + 'rpx'"> <block v-for="(item, index) in devicesList" :key="index"> <view class="list-item" :id="item.deviceId" @tap="Connect"> <view style="display:flex;flex-direction:column;width:80%"> <text style="font-size:medium;word-break:break-all">设备名称: {{item.name}}</text> <text style="font-size:x-small;color:gray;word-break:break-all">设备ID: {{item.deviceId}}</text> <text style="font-size:x-small;color:gray;word-break:break-all">信号强度RSSI: {{item.RSSI}}</text> </view> <image style="width:36px;height:36px" mode="aspectFit" src="/static/images/bluetooth.png"></image> </view> </block> </scroll-view> <button type="primary" class="button" :loading="searching" @tap="Search">{{searching?"搜索中...":"搜索蓝牙设备"}}</button> </view>
CSS
page { background-color: #f8f8f8; } .container { padding: 0 30rpx 0 30rpx; align-items: center; } .list-item { display: flex; flex-direction: row; justify-content: space-between; align-items: center; width: 100%; padding: 10px 0 10px 0; box-sizing: border-box; border: 1px solid #000; border-style: none none solid none; border-bottom-color: lightgray; } .list-item:last-child { border-style: none; } .button { position: fixed; width: 690rpx; bottom: 30rpx; }
JS
const app = getApp(); export default { data() { return { searching: false, devicesList: [], list_height: "" }; }, components: {}, props: {}, onLoad: function (options) { var that = this; var list_height = (app.globalData.SystemInfo.windowHeight - 50) * (750 / app.globalData.SystemInfo.windowWidth) - 60; that.setData({ list_height: list_height }); uni.onBluetoothAdapterStateChange(function (res) { that.setData({ searching: res.discovering }); if (!res.available) { that.setData({ searching: false }); } }); uni.onBluetoothDeviceFound(function (devices) { //剔除重复设备,兼容不同设备API的不同返回值 var isnotexist = true; if (devices.deviceId) { if (devices.advertisData) { devices.advertisData = app.globalData.buf2hex(devices.advertisData); } else { devices.advertisData = ''; } console.log(devices); for (var i = 0; i < that.devicesList.length; i++) { if (devices.deviceId == that.devicesList[i].deviceId) { isnotexist = false; } } if (isnotexist) { that.devicesList.push(devices); } } else if (devices.devices) { if (devices.devices[0].advertisData) { devices.devices[0].advertisData = app.globalData.buf2hex(devices.devices[0].advertisData); } else { devices.devices[0].advertisData = ''; } console.log(devices.devices[0]); for (var i = 0; i < that.devicesList.length; i++) { if (devices.devices[0].deviceId == that.devicesList[i].deviceId) { isnotexist = false; } } if (isnotexist) { that.devicesList.push(devices.devices[0]); } } else if (devices[0]) { if (devices[0].advertisData) { devices[0].advertisData = app.globalData.buf2hex(devices[0].advertisData); } else { devices[0].advertisData = ''; } console.log(devices[0]); for (var i = 0; i < devices_list.length; i++) { if (devices[0].deviceId == that.devicesList[i].deviceId) { isnotexist = false; } } if (isnotexist) { that.devicesList.push(devices[0]); } } that.setData({ devicesList: that.devicesList }); }); }, onReady: function () {}, onShow: function () {}, onHide: function () { var that = this; that.setData({ devicesList: [] }); if (this.searching) { uni.stopBluetoothDevicesDiscovery({ success: function (res) { console.log(res); that.setData({ searching: false }); } }); } }, methods: { Search: function () { var that = this; if (!that.searching) { uni.closeBluetoothAdapter({ complete: function (res) { console.log(res); uni.openBluetoothAdapter({ success: function (res) { console.log(res); uni.getBluetoothAdapterState({ success: function (res) { console.log(res); } }); uni.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, success: function (res) { console.log(res); that.setData({ searching: true, devicesList: [] }); } }); }, fail: function (res) { console.log(res); uni.showModal({ title: '提示', content: '请检查手机蓝牙是否打开', showCancel: false, success: function (res) { that.setData({ searching: false }); } }); } }); } }); } else { uni.stopBluetoothDevicesDiscovery({ success: function (res) { console.log(res); that.setData({ searching: false }); } }); } }, Connect: function (e) { var that = this; var advertisData, name; console.log(e.currentTarget.id); for (var i = 0; i < that.devicesList.length; i++) { if (e.currentTarget.id == that.devicesList[i].deviceId) { name = that.devicesList[i].name; advertisData = that.devicesList[i].advertisData; } } uni.stopBluetoothDevicesDiscovery({ success: function (res) { console.log(res); that.setData({ searching: false }); } }); uni.showLoading({ title: '连接蓝牙设备中...' }); uni.createBLEConnection({ deviceId: e.currentTarget.id, success: function (res) { console.log(res); uni.hideLoading(); uni.showToast({ title: '连接成功', icon: 'success', duration: 1000 }); uni.navigateTo({ url: '../device/device?connectedDeviceId=' + e.currentTarget.id + '&name=' + name }); }, fail: function (res) { console.log(res); uni.hideLoading(); uni.showModal({ title: '提示', content: '连接失败', showCancel: false }); } }); } } };
效果图

二、接收和发送指令给蓝牙设备
HTML
<view class="container"> <text style="font-size:medium;word-break:break-all">设备名称:{{name}}</text> <text style="font-size:x-small;color:gray;word-break:break-all">设备ID:{{connectedDeviceId}}</text> <text style="font-size:x-small;color:gray">状态:{{connected?"已连接":"已断开"}}</text> <text style="font-size:medium;margin-top:10px">接收内容:</text> <textarea class="res" maxlength="-1" disabled :value="receiveText"></textarea> <text> \n </text> <text style="font-size:medium;margin-top:10px">发送内容:</text> <input class="input" :value="inputText" @input="bindInput" maxlength="20"> <button type="primary" class="button" @tap="Send">发送</button> </view>
CSS
page { background-color: #f8f8f8; } .container { padding: 30rpx; align-items: left; } .input { margin-top: 3px; width: 100%; border: 1px solid lightgray; border-radius: 6px; } .res { margin-top: 3px; width: 100%; border: 3px solid lightgray; border-radius: 6px; } .button { position: fixed; width: 690rpx; bottom: 30rpx; }
JS
const app = getApp(); export default { data() { return { inputText: 'mootek', receiveText: '', name: '', connectedDeviceId: '', services: {}, characteristics: {}, connected: true, searching: false, serviceId: "", characteristicId: "" }; }, components: {}, props: {}, onLoad: function(options) { console.log(options) var that = this; that.setData({ name: options.name, connectedDeviceId: options.connectedDeviceId }); uni.getBLEDeviceServices({ deviceId: that.connectedDeviceId, success: function(res) { console.log(res.services); that.setData({ services: res.services, serviceId: res.services[0].uuid }); uni.getBLEDeviceCharacteristics({ deviceId: options.connectedDeviceId, serviceId: that.serviceId, success: function(res) { console.log(res.characteristics); that.setData({ characteristics: res.characteristics, characteristicId: res.characteristics[1].uuid }); uni.notifyBLECharacteristicValueChange({ state: true, deviceId: options.connectedDeviceId, serviceId: that.serviceId, characteristicId: that.characteristicId, success: function(res) { console.log('启用notify成功:' + that .characteristicId); console.log(JSON.stringify(res)); that.onBLECharacteristicValueChange(); }, fail: function() { console.log('开启notify失败' + that .characteristicId); } }); } }); } }); uni.onBLEConnectionStateChange(function(res) { console.log(res.connected); that.setData({ connected: res.connected }); }); }, onReady: function() {}, onShow: function() {}, onHide: function() {}, methods: { bindInput: function(e) { this.setData({ inputText: e.detail.value }); console.log(e.detail.value); }, Send: function() { var that = this; if (that.connected) { var buffer = new ArrayBuffer(that.inputText.length); var dataView = new Uint8Array(buffer); console.log(buffer, dataView) for (var i = 0; i < that.inputText.length; i++) { dataView[i] = that.inputText.charCodeAt(i); } uni.writeBLECharacteristicValue({ deviceId: that.connectedDeviceId, serviceId: that.serviceId, characteristicId: that.characteristicId, value: buffer, success: function(res) { console.log('发送指令成功:' + res.errMsg); uni.showModal({ title: '数据发送成功', content: '' }); }, fail: function(res) { // fail //console.log(that.data.services) console.log('message发送失败:' + res.errMsg); uni.showToast({ title: '数据发送失败,请稍后重试', icon: 'none' }); } }); } else { uni.showModal({ title: '提示', content: '蓝牙已断开', showCancel: false, success: function(res) { that.setData({ searching: false }); } }); } }, onBLECharacteristicValueChange: function() { console.log('onBLECharacteristicValueChange'); var that = this; console.log(uni.onBLECharacteristicValueChange); uni.onBLECharacteristicValueChange(function(res) { console.log('1'); console.log('监听低功耗蓝牙设备的特征值变化事件成功', res.value); console.log(app.globalData.buf2string(res.value)); if (that.inputText == 'rcd[1]') { var data = app.globalData.Str2Bytes(res.value); console.log(app.globalData.Str2Bytes(res.value)) var receiveText = app.globalData.buf2string(data); }else{ var receiveText = app.globalData.buf2string(res.value); } that.setData({ receiveText: receiveText }); }); } } };
APP.vue 代码
CSS
/**app.wxss**/ .container { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 200rpx 0; box-sizing: border-box; }
JS
globalData: { buf2hex: function (buffer) { return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); }, buf2string: function (buffer) { var arr = Array.prototype.map.call(new Uint8Array(buffer), x => x); var str = ''; console.log(buffer) for (var i = 0; i < arr.length; i++) { str += String.fromCharCode(arr[i]); } return str; }, Str2Bytes(str) { var pos = 0; var len = str.length; if(len %2 != 0) { return null; } len /= 2; var hexA = new Array(); for(var i=0; i<len; i++) { var s = str.substr(pos, 2); var v = parseInt(s, 16); hexA.push(v); pos += 2; } return hexA; }, SystemInfo: {} }, onLaunch: function () { this.globalData.SystemInfo = uni.getSystemInfoSync(); //console.log(this.globalData.SystemInfo) }, methods: {} };
浙公网安备 33010602011771号