蓝牙控制阀小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

612 lines
15 KiB

<template>
<view >
<view class="content" v-if="!connected">
<u-icon class="logo" size="300" color="#808080" @click="scanDevice" name="scan"></u-icon>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
<view v-else style="margin-top: 300rpx;padding-left: 10px;">
<u-row gutter="16">
<u-col span="7">
<view ><u-slider :height="20" @end="kiTovalue" v-model="valueki" step="10"></u-slider></view>
</u-col>
<u-col span="4" offset="1">
<u-number-box v-model="value" :min="0" :max="10" @change="valueToki"/>
</u-col>
</u-row>
<u-row gutter="16" >
<u-col span="3">
<u-button plain size="mini" type="success" @click="sendValue">确认发送</u-button>
</u-col>
<u-col span="3">
<u-button plain size="mini" type="error" @click="closeBLEConnection">断开连接</u-button>
</u-col>
<u-col span="3">
<u-button plain size="mini" type="warning" @click="writeBLECharacteristicValueString('getd')">获取开合度</u-button>
</u-col>
</u-row>
</view>
<u-modal @cancel='stopBluetoothDevicesDiscovery,show=false' title="提示" content="未搜索到设备,是否继续搜索" :show-cancel-button="true" @confirm="continueSearch()" v-model="searchLoad" >
</u-modal>
<u-toast ref="uToast" />
</view>
</template>
<script>
export default {
data() {
return {
searchLoad:false,
valueki:0,
value: 0,
title: '扫描设备二维码',
equipment: {},
connected: false,
isStop: true,
list: [],
imei: '',
item: [],
idObject:{
serviceId:'',
writeId:'',
notifyId:'',
},
timeSearch:null,
};
},
onLoad() {
this.onBLEConnectionStateChange();
},
onUnload:function(){
if(this.timeSearch) {
clearTimeout(this.timeSearch)
this.timeSearch = null
}
},
methods: {
kiTovalue(){
this.value=this.valueki/10
},
valueToki(){
this.valueki=this.value*10
},
sendValue() {
this.writeBLECharacteristicValueString('vals'+this.value)
},
continueSearch(){
clearTimeout(this.timeSearch)
this.timeSearch=setTimeout(() => {
if(!this.searchLoad&&!this.connected){
this.searchLoad=true
}
}, 8000);
uni.showToast({
title: '搜索设备中...',
icon: 'loading',
duration: 8000
});
this.startBluetoothDevicesDiscovery();
},
scanDevice() {
uni.openBluetoothAdapter({
success: e => {
var that = this
uni.scanCode({
success: function(res) {
let str1 = res.result.replace(';', '');
that.imei = str1
uni.showToast({
title: '搜索设备中...',
icon: 'loading',
duration: 8000
});
that.timeSearch=setTimeout(() => {
if(!that.searchLoad&&!that.connected){
that.searchLoad=true
}
}, 8000);
that.startBluetoothDevicesDiscovery();
},
fail: (res) => {
/* this.$refs.uToast.show({
title: '已取消',
type: 'error',
}) */
}
});
this.getBluetoothAdapterState();
},
fail: e => {
console.log(e)
console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));
if (e.errCode !== 0) {
initTypes(e.errCode, e.errMsg);
}
}
});
},
/**
* 初始化蓝牙设备
*/
openBluetoothAdapter() {
uni.openBluetoothAdapter({
success: e => {
console.log('初始化蓝牙成功:' + e.errMsg);
console.log(JSON.stringify(e));
this.isStop = false;
this.getBluetoothAdapterState();
},
fail: e => {
console.log(e)
console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));
if (e.errCode !== 0) {
initTypes(e.errCode, e.errMsg);
}
}
});
},
/**
* 开始搜索蓝牙设备
*/
startBluetoothDevicesDiscovery() {
uni.startBluetoothDevicesDiscovery({
success: e => {
this.onBluetoothDeviceFound();
},
fail: e => {
console.log('搜索蓝牙设备失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery(types) {
clearTimeout(this.timeSearch)
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log('停止搜索蓝牙设备:' + e.errMsg);
},
fail: e => {
console.log('停止搜索蓝牙设备失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
uni.onBluetoothDeviceFound(devices => {
// this.$set(this.disabled, 3, false);
this.getBluetoothDevices();
});
},
/**
* 获取在蓝牙模块生效期间所有已发现的蓝牙设备。包括已经和本机处于连接状态的设备。
*/
getBluetoothDevices() {
// this.list=[]
let that = this
let imei = that.imei
uni.getBluetoothDevices({
success: res => {
res.devices.forEach(device => {
if (!device.name.indexOf('tpsl04v-' + imei.substr(imei.length - 6))) {
uni.hideToast();
that.stopBluetoothDevicesDiscovery()
that.equipment = device;
that.createBLEConnection()
return
} else {
//that.list.push(device)
}
})
},
fail: e => {
console.log('获取蓝牙设备错误,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 获取本机蓝牙适配器状态
*/
getBluetoothAdapterState() {
console.log('--->');
uni.getBluetoothAdapterState({
success: res => {
console.log(JSON.stringify(res));
},
fail: e => {
console.log('获取本机蓝牙适配器状态失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 连接低功耗蓝牙
*/
createBLEConnection() {
let deviceId = this.equipment.deviceId;
uni.showToast({
title: '连接蓝牙...',
icon: 'loading',
duration: 99999
});
if (!this.connected) {
uni.createBLEConnection({
deviceId,
success: res => {
this.connected = true;
clearTimeout(this.timeSearch)
console.log(res);
console.log('连接蓝牙成功:' + res.errMsg);
// 连接设备后断开搜索 并且不能搜索设备
uni.hideToast();
uni.showToast({
title: '连接成功',
icon: 'success',
duration: 2000
});
// this.closeBLEConnection()
this.getBLEDeviceServices()
},
fail: e => {
uni.hideToast();
/* uni.showToast({
title: '连接错误',
icon: 'error',
duration: 2000
}); */
console.log('连接低功耗蓝牙失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
}
},
/**
* 断开与低功耗蓝牙设备的连接
*/
closeBLEConnection() {
let deviceId = this.equipment.deviceId;
this.connected = false
uni.closeBLEConnection({
deviceId,
success: res => {
console.log(res);
console.log('断开低功耗蓝牙成功:' + res.errMsg);
this.equipment = {};
this.idObject={}
},
fail: e => {
console.log('断开低功耗蓝牙成功,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 获取所有服务
*/
getBLEDeviceServices() {
let deviceId = this.equipment.deviceId;
uni.getBLEDeviceServices({
deviceId,
success: res => {
this.list = res.services;
this.idObject = {};
if (this.list.length <= 0) {
toast('获取服务失败,请重试!');
return;
}
this.list.forEach(item => {
this.getBLEDeviceCharacteristics(item)
})
this.maskShow = true;
},
fail: e => {
console.log('获取设备服务失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 获取某个服务下的所有特征值
*/
getBLEDeviceCharacteristics(item) {
let deviceId = this.equipment.deviceId;
let serviceId = item.uuid;
let that = this
let write=''
let notify=''
uni.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: res => {
this.list = res.characteristics;
if (this.list.length <= 0) {
// toast('获取特征值失败,请重试!');
return;
}
this.list.forEach(characteristic => {
/* if (characteristic.properties.read) {
uni.readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId: characteristic.uuid,
success: res => {
console.log('读取设备数据值成功read');
console.log(JSON.stringify(res));
},
fail(e) {
console.log('读取设备数据值失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
} */
if (characteristic.properties.write ) {
write=characteristic.uuid
}
if (characteristic.properties.notify || characteristic.properties.indicate) {
notify=characteristic.uuid
}
})
if(write!==''&&notify!==''){
this.idObject={
serviceId:serviceId,
writeId:write,
notifyId:notify,
}
console.log(this.idObject)
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId,
serviceId,
characteristicId: this.idObject.notifyId,
success(res) {
that.onBLECharacteristicValueChange()
setTimeout(() => {
that.writeBLECharacteristicValueString('getd')
}, 1000);
},
fail(e) {
console.log('失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
}
},
fail: e => {
console.log('获取特征值失败,错误码:' + e.errCode);
if (e.errCode !== 0) {
initTypes(e.errCode);
}
}
});
},
/**
* 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等
*/
onBLEConnectionStateChange() {
uni.onBLEConnectionStateChange(res => {
// 该方法回调中可以用于处理连接意外断开等异常情况
console.log(`蓝牙连接状态 -------------------------->`);
console.log(JSON.stringify(res));
if (!res.connected) {
this.connected=false
console.log('断开低功耗蓝牙成功:');
this.equipment = {};
this.idObject={}
toast('已经断开当前蓝牙连接');
}
});
},
writeBLECharacteristicValueString(str) {
console.log(str)
let deviceId = this.equipment.deviceId;
let serviceId = this.idObject.serviceId;
let characteristicId = this.idObject.writeId;
// 向蓝牙设备发送16进制数据
let buffer = new ArrayBuffer(str.length);
let dataView = new DataView(buffer);
for (let i in str) {
dataView.setUint8(i, str[i].charCodeAt() | 0);
}
uni.writeBLECharacteristicValue({
deviceId,
serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId,
value: buffer,
success: function(res) {
console.log(res);
},
fail: function(res) {
console.log(res);
}
})
},
// 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('')
},
/**
* 监听低功耗蓝牙设备的特征值变化事件。必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification。
*/
onBLECharacteristicValueChange() {
// 必须在这里的回调才能获取
let that = this
uni.onBLECharacteristicValueChange(function(res) {
console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
// console.log(that.ab2hex(res.value))
console.log(res)
let hex = new Uint8Array(res.value);
hex = String.fromCharCode.apply(null, hex);
that.value= parseInt(hex.replace('valve status: ', ''));
that.valueki=parseInt(hex.replace('valve status: ', ''))*10;
console.log(that.value)
})
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter(OBJECT) {
uni.closeBluetoothAdapter({
success: res => {
console.log('断开蓝牙模块成功');
this.equipment = {};
this.idObject={}
toast('断开蓝牙模块');
}
});
}
}
};
/**
* 判断初始化蓝牙状态
*/
function initTypes(code, errMsg) {
switch (code) {
case 10000:
console.log('未初始化蓝牙适配器');
break;
case 10001:
toast('未检测到蓝牙,请打开蓝牙重试!');
break;
case 10002:
console.log('没有找到指定设备');
break;
case 10003:
console.log('连接失败');
break;
case 10004:
console.log('没有找到指定服务');
break;
case 10005:
console.log('没有找到指定特征值');
break;
case 10006:
console.log('当前连接已断开');
break;
case 10007:
console.log('当前特征值不支持此操作');
break;
case 10008:
console.log('其余所有系统上报的异常');
break;
case 10009:
console.log('Android 系统特有,系统版本低于 4.3 不支持 BLE');
break;
default:
console.log(errMsg);
}
}
/**
* 弹出框封装
*/
function toast(content, showCancel = false) {
uni.showModal({
title: '提示',
content,
showCancel
});
}
</script>
<style>
page {
height: 100%;
width: 100%;
}
.content {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
margin: 0;
padding: 0;
margin-top: 300rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.u-row {
margin: 40rpx 0;
}
</style>