<template>
<view class="content">
<toplogo/>
<view class="mtop-10">
<button type="primary" @click="btnStarSearch">搜索设备</button>
</view>
<view>
<button type="primary" class=" mtop-10" @click="sendDataToBluetooth" v-if="writeFlag">发送数据到蓝牙设备</button>
</view>
<view>
<button type="primary" class=" mtop-10" @click="notifyStart" v-if="notifyFlag">启动数据接受</button>
</view>
<view>
<view>notify信息接受</view>
<view>{{notifyData}}</view>
</view>
<view class="connectItem mtop-10">
<view class="notify-item">
<view>notify设备特征信息</view>
<view>设备ID:{{notifyServerItem.deviceId}}</view>
<view>服务ID:{{notifyServerItem.serverId}}</view>
<view>特征ID:{{notifyServerItem.characterId}}</view>
</view>
<view class="">
<view>read发送特征信息</view>
<view>设备ID:{{readServerItem.deviceId}}</view>
<view>服务ID:{{readServerItem.serverId}}</view>
<view>特征ID:{{readServerItem.characterId}}</view>
</view>
<view class="">
<view>write设备特征信息</view>
<view>设备ID:{{writeServerItem.deviceId}}</view>
<view>服务ID:{{writeServerItem.serverId}}</view>
<view>特征ID:{{writeServerItem.characterId}}</view>
</view>
</view>
<view class="mtop-10 blue-data-list">
<view>蓝牙调试数据</view>
<view>
<view class="device-item" v-for="(item,index) in showBlueDate">
<view class="device-title">
<view class="device-name"> <view>设备名称:{{item.name}}</view> <view class="connect-status">状态:{{connectStatus?'已连接':'未链接'}}</view> </view>
<view>设备ID:{{item.deviceId}}</view>
</view>
<view class="mtop-10">
<view>服务ID列表</view>
<view class="one-connect-item" v-for="(server_item,server_index) in serverList">
<view class="device-title">
<view class="connect-btn" @click="connectServeId(server_item)">服务ID :{{server_item.uuid}}</view>
</view>
<!-- <view >
<view class="one-connect-item" v-for="( characterid_item, characterid_index) in server_item.characteridList">
<view class="connect-btn" @click="connectCharacterid(characterid_item)">特征码:{{characterid_item.uuid}}</view>
<view @click="connectCharacterid(characterid_item)">notify:{{characterid_item.properties.notify}},write:{{characterid_item.properties.write}},read:{{characterid_item.properties.read}}</view>
</view>
</view> -->
</view>
</view>
<view class="mtop-10 "> <button type="primary" @click="connectDevice(item,index)">连接调试设备</button></view>
</view>
</view>
</view>
<!-- 调试信息 -->
<view class="set-content">
<!-- 压力和频率设置列表 -->
<view class="setlist">
<view class="setitem mtop-10" v-for="(item,index) in setListTest">
<view class="show-info">
<view class="item-name">{{item.title}}</view>
<view class="item-name mleft-30">返回值:{{item.read_value}}</view>
</view>
<view class="set-item-content">
<view class="item-readadd">地址:{{item.read_add}}</view>
<view class="item-value mleft-30">
<input :placeholder="item.tip" type="number" maxlength="4" :value="item.setValue" :disabled="(item.read_write=='R')? true : false" v-show="item.read_write=='RW'?true:false" />
</view>
<view class="item-btnset mleft-30">
<button type="primary" v-show="item.read_write=='RW'? true : false">设置</button>
</view>
<!-- <view class="item-readorwrite mleft-30">{{item.read_write}}</view> -->
</view>
</view>
<view class="setitem mtop-10" v-for="(itemaddr,index) in showBitTest">
<view class="show-info">
<view class="item-name">{{itemaddr.title}}</view>
<view class="item-name mleft-30">返回值:{{itemaddr.read_value}}</view>
</view>
<view class="set-item-content">
<view class="item-readadd">地址:{{itemaddr.read_add}}</view>
<view class="item-value mleft-30">
<!-- <input :placeholder="itemaddr.tip" type="number" maxlength="4" :value="itemaddr.setValue" :disabled="(itemaddr.read_write=='R')? true : false" v-show="itemaddr.read_write=='RW'?true:false" /> -->
</view>
<view class="item-btnset mleft-30">
<!-- <button type="primary" v-show="itemaddr.read_write=='RW'? true : false">设置</button> -->
</view>
<!-- <view class="item-readorwrite mleft-30">{{item.read_write}}</view> -->
</view>
</view>
</view>
<!-- 功能寄存器地址 -->
<view>
</view>
</view>
<view class="tooth-list">
<view class="one-tooth mtop-20" v-for="(item,index) in deviceListTest" >
<view>设备信息</view>
<view class="one-content">
<view class="one-line">
{{item}}
</view>
<view class="one-line">
<view class="one-line-title">RSSI:</view>
<view class="one-line-content">{{item.RSSI}}</view>
</view>
<view class="one-line">
<view class="one-line-title">advertisData:</view>
<view class="one-line-content">{{item.advertisData}}</view>
</view>
<view class="one-line">
<view class="one-line-title">advertisServiceUUIDs:</view>
<view class="one-line-content">{{item.advertisServiceUUIDs}}</view>
</view>
<view class="one-line">
<view class="one-line-title">connectable:</view>
<view class="one-line-content">{{item.connectable}}</view>
</view>
<view class="one-line">
<view class="one-line-title">deviceId:</view>
<view class="one-line-content">{{item.deviceId}}</view>
</view>
<view class="one-line">
<view class="one-line-title">localName:</view>
<view class="one-line-content">{{item.localName}}</view>
</view>
<view class="one-line">
<view class="one-line-title">name:</view>
<view class="one-line-content">{{item.name}}</view>
</view>
<view class="one-line">
<view class="one-line-title">serviceData:</view>
<view class="one-line-content">{{item.serviceData}}</view>
</view>
<view class="one-line">
<view> <button type="primary" @click="connectDevice(item)">连接设备</button> </view>
</view>
</view>
</view>
</view>
<view class="bottom-vew"></view>
</view>
</template>
<script>
import toplogo from '../index/topLogo.vue';
export default {
components:{
toplogo
},
data() {
return {
readFlag:false,
writeFlag:false,
notifyFlag:false,
setListTest:[],
notifyData:"",
notifyServerItem:{serverId:null,deviceId:null,characterId:null},
readServerItem:{serverId:null,deviceId:null,characterId:null},
writeServerItem:{serverId:null,deviceId:null,characterId:null},
readBLECharacterID:0,
writeBLEcharacterID:0,
notifyBLEcharacterID:0,// 可监听的特征值
serverList:[],//服务列表地址
characteridList:[],///特征码地址
connectDeviceItem:null,
connectFlag:false,
showBlueDate:[],
deviceListTest:[],
showBitTest:[],
showBit:[
],
setList:[
],
characteristicId:"",
services:[],
deviceList:[
],
connectBluetooth:{}
}
},
computed:{},
onLoad() {
let that=this
// console.log(this.$store.state)
},
methods: {
hexCharCodeToStr(hexCharCodeStr) {
var trimedStr = hexCharCodeStr.trim();
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));
}
return resultStr.join("");
},
ab2hex(buffer){
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
connectServeId(id){
let that =this
that.serviceId=id
},
connectCharacterid(id){
let that =this
that.characteristicId=id
},
showBLEdate(){
let that =this
uni.onBLECharacteristicValueChange(res => {
// 结果
console.log(res)
that.notifyData=that.notifyData+1
// 结果里有个value值,该值为 ArrayBuffer 类型,所以在控制台无法用肉眼观察到,必须将该值转换为16进制
let resHex = that.ab2hex(res.value)
console.log(resHex)
let result = that.hexCharCodeToStr(resHex)
console.log(result)
})
}
,
notifyStart(){
let that =this
uni.notifyBLECharacteristicValueChange({
state: true,
deviceId:that.notifyServerItem.deviceId,
serviceId:that.notifyServerItem.serverId,
characteristicId:that.notifyServerItem.characterId,
success (res) {
console.log('启动notify成功')
that.showBLEdate()
}
})
}
,
sendDataToBluetooth(){
let that =this
// 向蓝牙设备发送一个0x00的16进制数据
let msg = 'hello'
const buffer = new ArrayBuffer(msg.length)
const dataView = new DataView(buffer)
// dataView.setUint8(0, 0)
for (var i = 0; i < msg.length; i++) {
dataView.setUint8(i, msg.charAt(i).charCodeAt())
}
uni.writeBLECharacteristicValue({
deviceId:that.writeServerItem.deviceId,
serviceId:that.writeServerItem.serverId, // 服务UUID,
characteristicId:that.writeServerItem.characterId, // 特征值,
value: buffer,
success(res) {
console.log(res,'消息发送成功')
},
fail(err) {
console.error(err)
}
})
},
// 向设备发送数据
writeBlueData() {
let obj = {
cmd: 3,
freq: 430125,
speakable: 1
};
let objStr = JSON.stringify(obj);
let buffer = new ArrayBuffer(objStr.length); // 每个字符占用2个字节
let bufView = new Uint8Array(buffer);
for (let i = 0; i < objStr.length; i++) {
bufView[i] = objStr.charCodeAt(i);
}
// bluetooth.writeData(buffer);
},
sendOrder(){
},
///监测验证位
crc16Modbus(buffer) {
var crc = 0xFFFF;
var i, j, l;
for (i = 0, l = buffer.length; i < l; i++) {
crc ^= buffer[i];
for (j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
// 将结果拆分为低字节和高字节
var crcLow = crc & 0xFF;
var crcHigh = (crc >> 8) & 0xFF;
// 返回校验结果
return [crcLow, crcHigh];
},
//建立连接
connectDevice(item,index=0){
let that =this
that.connectDeviceItem=item
that.deviceId=item.deviceId
uni.createBLEConnection({
deviceId: item.deviceId,
success:(res)=>{
console.log('连接成功',res)
wx.showToast({
title: '连接成功',
icon:'none'
})
that.getServiceId(item,index)
},
fail:(err)=>{
wx.showToast({
title: '连接失败',
icon:'none'
})
}
})
},
getAllCharacteId(deviceId,serviceId){
let that =this
uni.getBLEDeviceCharacteristics({
deviceId:deviceId,
serviceId:serviceId,
success:(res)=>{
console.log('服务UUI特征值信息:',res)
// that.serverList[index].characteridList=res.characteristics
res.characteristics.map((characterItem)=>{
that.serverId=serviceId
if(characterItem.properties.notify==true&&that.notifyFlag==false){
console.log('服务notify特征值:',res)
that.notifyServerItem.characterId=characterItem.uuid
that.notifyServerItem.deviceId=deviceId
that.notifyServerItem.serverId=serviceId
that.notifyFlag=true
that.notifyStart()
}
if(characterItem.properties.read==true&&that.readFlag==false){
console.log('服务read特征值:',res)
that.readServerItem.characterId=characterItem.uuid
that.readServerItem.deviceId=deviceId
that.readServerItem.serverId=serviceId
that.readFlag=true
}
if(characterItem.properties.write==true&&that.writeFlag==false){
console.log('服务writeServerItem特征值:',res)
that.writeServerItem.characterId=characterItem.uuid
that.writeServerItem.deviceId=deviceId
that.writeServerItem.serverId=serviceId
that.writeFlag=true
}
})
},
fail:(err)=>{
console.log(err)
}
})
}
,
showReadInfo(){
uni.onBLECharacteristicValueChange()
}
,
getServiceId(item,index=0){
//获取服务ID
let that= this
that.connectDeviceItem=item
///循环检测
let listi=0;
let notifyitem=false
let writeitem=false
let readitem=false
wx.getBLEDeviceServices({
deviceId:that.connectDeviceItem.deviceId,
success:(res)=>{
that.serverList=res.services
let okserver=res.services[0]
res.services.map((serverItem)=>{
that.getAllCharacteId(that.connectDeviceItem.deviceId,serverItem.uuid)
})
},
fail:(err)=>{
console.log(err)
}
})
},
getReadCharacteId(deviceId,serviceId,index){
let that =this
uni.getBLEDeviceCharacteristics({
deviceId:deviceId,
serviceId:serviceId,
success:(res)=>{
console.log('服务UUI特征值信息:',res)
that.serverList[index].characteridList=res.characteristics
res.characteristics.map((characterItem)=>{
that.serverId=serviceId
if(characterItem.properties.read==true){
that.readServerItem.characterId=characterItem.uuid
that.readServerItem.deviceId=deviceId
that.readServerItem.serverId=serviceId
that.readFlag=true
}
})
},
fail:(err)=>{
console.log(err)
}
})
}
,
getWriteCharacteId(deviceId,serviceId,index){
let that =this
uni.getBLEDeviceCharacteristics({
deviceId:deviceId,
serviceId:serviceId,
success:(res)=>{
console.log('发送数据请求测试')
that.serverList[index].characteridList=res.characteristics
res.characteristics.map((characterItem)=>{
that.serverId=serviceId
if(characterItem.properties.write==true){
that.writeServerItem.characterId=characterItem.uuid
that.writeServerItem.deviceId=deviceId
that.writeServerItem.serverId=serviceId
that.writeFlag=true
}
})
},
fail:(err)=>{
console.log(err)
}
})
},
getNotifyCharacteId(deviceId,serviceId,index){
let that =this
uni.getBLEDeviceCharacteristics({
deviceId:deviceId,
serviceId:serviceId,
success:(res)=>{
console.log()
that.serverList[index].characteridList=res.characteristics
res.characteristics.map((characterItem)=>{
that.serverId=serviceId
if(characterItem.properties.indicate||characterItem.properties.notify){
that.notifyServerItem.characterId=characterItem.uuid
that.notifyServerItem.deviceId=deviceId
that.notifyServerItem.serverId=serviceId
that.notifyFlag=true
}
})
},
fail:(err)=>{
console.log(err)
}
})
},
getCharacteId(deviceId,serviceId,index){
let that =this
uni.getBLEDeviceCharacteristics({
deviceId:deviceId,
serviceId:serviceId,
success:(res)=>{
console.log('服务services列表信息:',res.services)
that.serverList[index].characteridList=res.characteristics
res.characteristics.map((characterItem)=>{
that.serverId=serviceId
if(characterItem.properties.write==true){
that.writeServerItem.characterId=characterItem.uuid
that.writeServerItem.deviceId=deviceId
that.writeServerItem.serverId=serviceId
}
})
},
fail:(err)=>{
console.log(err)
}
})
},
startNotice(){
let that =this
uni.notifyBLECharacteristicValueChange({
characteristicId:that.notifyServerItem.characterId,
deviceId:that.notifyServerItem.deviceId,
serviceId:that.notifyServerItem.serviceId,
state:true,
success(notify_res) {
console.log('蓝牙设备notify监听成功',notify_res)
//开始监听发送值
that.sendToDevice(notify_res)
},complete(notify_res) {
console.log('蓝牙设备notify监听成功',notify_res)
}
})
},
sendToDevice(send_info){
let that =this
console.log('发生信息')
///监听设备状态改变
wx.onBLEConnectionStateChange((res)=>{
console.log(res.value)
let a=res.value
let int8array=new Int8Array(a)
console.log('监听到特征值更新',int8array[0])
// that.write(a)
})
},
string2buffer (str) {
// var hexStr = 'cf03000000001e59ce967f010000a5'
var typedArray = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
var buf = typedArray.buffer
return buf;
// return new Uint8Array(
// str.match(/[\da-f]{2}/gi).map(function (h) {
// return parseInt(h, 16);
// })
// ).buffer;
},
// ArrayBufer 转字符串
buf2str (buffer) {
let encodedString = String.fromCodePoint.apply(
null,
new Uint8Array(buffer)
);
let decodedString = decodeURIComponent(escape(encodedString));
//没有这一步中文会乱码
return decodedString;
},
bufToHex(buffer) {
return Array.prototype.map
.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2))
.join('');
},
str2ab(value){
return value;
}
,
writeToDevice(value){///发送数据到链接设备
let that=this
wx.writeBLECharacteristicValue({
characteristicId: that.connectBluetooth.characteristicId,
deviceId: that.connectBluetooth.deviceId,
serviceId: that.serviceId,
value: this.str2ab(value),
success:(res)=>{
console.log(res,'发送数据')
},
fail:(err)=>{
console.log(res,'发送数据失败')
}
})
wx.readBLECharacteristicValue({
characteristicId: this.data.characteristicId,
deviceId: this.data.deviceId,
serviceId: this.data.serviceId,
success:(res)=>{
console.log(res)
}
})
},
btnStarSearch(){
this.initBluetoothAdapter()
},
getBLEDeviceServices(items,index) {
console.log('连接设备',items)
setTimeout(() => {
uni.getBLEDeviceServices({
deviceId: items.deviceId,
success: (res) => {
// console.log("成功",res)
console.log("设备 services:", res);
//这里会获取到好多个services uuid 我们只存储我们需要用到的就行,这个uuid一般硬件厂家会给我们提供
console.log("获取services", res.services);
},fail() {
console.log("连接设备失败", res);
}
});
}, 2000);
},
// item 是要连接的设备数据
createBLEConnection(item) {
console.log("申请连接设备:",item)
if(!item.connectable){
uni.showToast({title:"蓝牙被占用无法连接",icon: "none",});
return;
}
let that = this;
uni.showLoading({title: "连接中,请稍等",mask: true,});
uni.createBLEConnection({
deviceId: item.deviceId,
success(res) {
console.log('创建蓝牙连接成功')
uni.stopBluetoothDevicesDiscovery();
// 停止搜索蓝牙
that.getBLEDeviceServices(item);
// 获取蓝牙的服务
},
fail(res)
{
uni.showToast({title: item.name + "蓝牙连接失败",icon: "none",});
uni.hideLoading()
}
});
},
onBluetoothDeviceFound() {
let that=this
uni.onBluetoothDeviceFound((res) => {
that.showBlueDate=that.showBlueDate+JSON.stringify(res)
let newBL={
RSSI:'test',
advertisData:'test',
advertisServiceUUIDs:'test',
connectable:'test',
deviceId:'test',
localName:'test',
name:'test',
serviceData:'test',
}
res.devices.map((item)=>{
if(item.name=='xz2023'||item.localName=='xz2023')
{
if(item.connectable){
that.deviceList.push(item)
}
}
})
})
},
searchBluetoothDevice(data){
let that=this
console.log(data,'蓝牙初始化成功')
///开始蓝牙设备搜索
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey:false,
success(res) {
uni.onBluetoothDeviceFound((device_list)=>{
device_list.devices.map((item_device)=>{
//只搜索蓝牙测试设备
if(item_device.name=='Nordic_UART'||item_device.deviceId=='D1:63:8D:12:71:13'){
item_device.connectStatus=false;
that.showBlueDate.push(item_device)
console.log(item_device,'蓝牙设备搜索监听')
console.log( typeof device_list.devices,'查询到设备列表')
}
})
})
}
})
},
蓝牙初始化
initBluetoothAdapter(){
let that=this
uni.openBluetoothAdapter({
success(res) {
that.searchBluetoothDevice(res);
console.log(res,'蓝牙初始化')
},
fail(err_res) {
console.log(err_res,'初始化错误')
uni.showToast({
icon:"error",
title:"蓝牙设备未开启",
duration:3000
})
}
})
}
},
}
</script>
<style lang="scss">
.blue-data-list{
display: flex;
flex-direction: column;
}
.device-item{
margin-top: 20rpx;
border-radius: 40rpx;
background-color: #fff;
display: flex;
flex-direction: column;
height: auto;
}
.one-connect-item{
display: flex;
flex-direction: column;
justify-content: space-around;
.connect-btn{
height: 80rpx;
}
}
.bottom-vew{
background-color: red;
width: 100%;
height: 120rpx;
}
.mleft-30{
margin-left: 30rpx;
}
.setlist{
display: flex;
flex-direction: column;
.set-item-content{
display: flex;
flex-direction: row;
justify-content: space-between;
justify-content: center;
align-items: center;
.item-btnset{
height: 80rpx;
width: 180rpx;
}
.item-value{
width: 280rpx;
}
}
.setitem{
padding: 20rpx;
border-radius: 20rpx;
background-color: #fff;
display: flex;
flex-direction: column;
.item-readadd{
width: 170rpx;
}
.show-info{
display: flex;
flex-direction: row;
}
}
}
.set-content{
padding-left: 10rpx;
padding-right: 10rpx;
margin-top: 20rpx;
display: flex;
flex-direction: row;
justify-content: flex-start;
input{
width: 260rpx;
border: #8f8f94 1px solid;
}
}
.tooth-list{
display: flex;
justify-content: center;
flex-direction: column;
width: 100%;
.one-tooth{
padding: 20rpx;
border-radius: 20rpx;
width: 100%;
background-color: #fff;
min-height: 160rpx;
.one-content{
display: flex;
flex-direction: column;
.one-line{
display: flex;
flex-direction: row;
.one-line-title{
width: 320rpx;
text-align: right;
height: 40rpx;
}
.one-line-content{
text-align: right;
width: 260rpx;
}
}
}
}
}
.btn-bg{
color: aliceblue;
background-color:$uni-color-primary;
}
.content {
overflow-x: hidden;
margin-bottom: 300rpx;
// overflow: scroll;
display: flex;
flex-direction: column;
justify-content: center;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.device-name{
display: flex;
flex-direction: row;
justify-content: space-around;
}
</style>