微信小程序 蓝牙设备连接,控制开关灯

1.前言

微信小程序中连接蓝牙设备,信息写入流程
1、检测当前使用设备(如自己的手机)是否支持蓝牙/蓝牙开启状态
wx:openBluetoothAdapter({})
2、如蓝牙已开启状态,检查蓝牙适配器的状态
wx.getBluetoothAdapterState({})
3、添加监听蓝牙适配器状态变化
wx.onBluetoothAdapterStateChange({})
4、搜索附近蓝牙设备
wx.startBluetoothDevicesDiscovery({})
5、监听搜索的到设备
wx.onBluetoothDeviceFound({})
遍历设备列表找到和macAddr(看自己家的蓝牙装置的物理地址)匹配的设备的deviceId
6、连接想要连接的切匹配成功的设备
wx.createBLEConnection({})
7、获取连接成功的设备的设备服务servicesID
wx.getBLEDeviceServices({})
8、获取设备特征id
wx.getBLEDeviceCharacteristics({})
9、向设备写入指令
wx.writeBLECharacteristicValue({})

以下是代码重点,本人亲测有效,集官网和百家之所长,汇聚之大成,入我门来,使君不负观赏

#2. 小程序前端index.wxml

<wxs module="utils">
module.exports.max = function(n1, n2) {return Math.max(n1, n2)
}
module.exports.len = function(arr) {arr = arr || []return arr.length
}
</wxs>
<button bindtap="openBluetoothAdapter"   class="primary-btn" >开始扫描</button>
<button bindtap="closeBLEConnection"  class="default-btn" >断开连接</button>
<button bindtap="opendeng"   class="sumit-btn" >开灯</button>
<button bindtap="guandeng"   class="warn-btn" >关灯</button><view class="devices_summary">已发现 {{devices.length}} 个外围设备:</view>
<scroll-view class="device_list" scroll-y scroll-with-animation><view wx:for="{{devices}}" wx:key="index"data-device-id="{{item.deviceId}}"data-name="{{item.name || item.localName}}"bindtap="createBLEConnection" class="device_item"hover-class="device_item_hover"><view style="font-size: 16px; color: #333;">{{item.name}}</view><view style="font-size: 10px">信号强度: {{item.RSSI}}dBm ({{utils.max(0, item.RSSI + 100)}}%)</view><view style="font-size: 10px">UUID: {{item.deviceId}}</view><view style="font-size: 10px">Service数量: {{utils.len(item.advertisServiceUUIDs)}}</view></view>
</scroll-view><view class="connected_info" wx:if="{{connected}}"><view><icon class="icon-box-img" type="success" size="33"></icon><view class="icon-box-text"> {{name}}连接成功!!!</view></view> </view>

3.小程序index.wxss


page {color: #333;
}
.icon-box-img{height: 20px;float: left;margin-left: 20%;
}
.icon-box-text{height: 30px;line-height: 30px;margin-left:5px;float: left;
}.primary-btn{margin-top: 30rpx;/* border: rgb(7, 80, 68) 1px solid; */color: rgb(241, 238, 238);background-color: rgb(14, 207, 46);
}
.default-btn{margin-top: 30rpx;/* border: #333 1px solid; */color: rgb(243, 236, 236);background-color: rgb(189, 112, 25);
}.warn-btn{margin-top: 30rpx;/* border: #333 1px solid; */color: rgb(240, 231, 231);background-color: rgb(235, 10, 10);
}
.sumit-btn{margin-top: 30px;width: 60px;color: rgb(240, 231, 231);background-color: rgb(10, 100, 235);
}.devices_summary {margin-top: 30px;padding: 10px;font-size: 16px;
}
.device_list {height: 300px;margin: 50px 5px;margin-top: 0;border: 1px solid #EEE;border-radius: 5px;width: auto;
}
.device_item {border-bottom: 1px solid #EEE;padding: 10px;color: #666;
}
.device_item_hover {background-color: rgba(0, 0, 0, .1);
}
.connected_info {position: fixed;bottom: 10px;width: 80%;margin-left: 6%;background-color: #F0F0F0;padding: 10px;padding-bottom: 20px;margin-bottom: env(safe-area-inset-bottom);font-size: 18px;/* line-height: 20px; */color: #1da54d;text-align: center;/* height: 20px; */box-shadow: 0px 0px 3px 0px;
}
.connected_info .operation {position: absolute;display: inline-block;right: 30px;
}

4.小程序 index.ts


const app = getApp()function inArray(arr, key, val) {for (let i = 0; i < arr.length; i++) {if (arr[i][key] === val) {return i;}}return -1;
}// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {var hexArr = Array.prototype.map.call(new Uint8Array(buffer),function (bit) {return ('00' + bit.toString(16)).slice(-2)})return hexArr.join('');
}Page({data: {devices: [],connected: false,chs: [],},getCeshi() {wx.navigateTo({url: '/pages/main/main',})},// 搜寻周边蓝牙openBluetoothAdapter() {//console.log('openBluetoothAdapter success')wx.openBluetoothAdapter({success: (res) => {console.log('openBluetoothAdapter success', res)this.startBluetoothDevicesDiscovery()},fail: (res) => {if (res.errCode === 10001) {wx.onBluetoothAdapterStateChange(function (res) {console.log('onBluetoothAdapterStateChange', res)if (res.available) {this.startBluetoothDevicesDiscovery()}})}}})},// 停止搜寻周边蓝牙getBluetoothAdapterState() {wx.getBluetoothAdapterState({success: (res) => {console.log('getBluetoothAdapterState', res)if (res.discovering) {this.onBluetoothDeviceFound()} else if (res.available) {this.startBluetoothDevicesDiscovery()}}})},// 开始搜寻附近的蓝牙外围设备startBluetoothDevicesDiscovery() {if (this._discoveryStarted) {return}this._discoveryStarted = truewx.startBluetoothDevicesDiscovery({allowDuplicatesKey: true,success: (res) => {console.log('startBluetoothDevicesDiscovery success', res)this.onBluetoothDeviceFound()},})},//停止搜寻附近的蓝牙外围设备。若已经找到需要的蓝牙设备并不需要继续搜索时,建议调用该接口停止蓝牙搜索。stopBluetoothDevicesDiscovery() {wx.stopBluetoothDevicesDiscovery()},//监听搜索到新设备的事件onBluetoothDeviceFound() {wx.onBluetoothDeviceFound((res) => {res.devices.forEach(device => {if (!device.name && !device.localName) {return}const foundDevices = this.data.devicesconst idx = inArray(foundDevices, 'deviceId', device.deviceId)const data = {}if (idx === -1) {data[`devices[${foundDevices.length}]`] = device} else {data[`devices[${idx}]`] = device}this.setData(data)})})},//连接蓝牙低功耗设备。createBLEConnection(e) {const ds = e.currentTarget.datasetconst deviceId = ds.deviceIdconst name = ds.namewx.createBLEConnection({deviceId,success: (res) => {this.setData({connected: true,name,deviceId,})this.getBLEDeviceServices(deviceId)}})this.stopBluetoothDevicesDiscovery()},closeBLEConnection() {wx.closeBLEConnection({deviceId: this.data.deviceId})this.setData({connected: false,chs: [],canWrite: false,})},//获取蓝牙低功耗设备所有服务。getBLEDeviceServices(deviceId) {console.log('deviceId ========', deviceId)wx.getBLEDeviceServices({deviceId,success: (res) => {for (let i = 0; i < res.services.length; i++) {//获取通过设备id多个特性服务serviceid (包含 读、写、通知、等特性服务)//   console.log('serviceId ========', res.services[2].uuid)// 通过上边注释解封,排查到判断服务id 中第三个服务id  代表写入服务//  isPrimary代表 :判断服务id是否为主服务// if (res.services[2].isPrimary) {//  this.getBLEDeviceCharacteristics(deviceId, res.services[2].uuid)//  }//判断通过(设备id获取的多个特性服务)中是否有与(蓝牙助手获取的写入特性服务),相一致的serviceidif (res.services[i].uuid=="0000FFE0-0000-1000-8000-00805F9B34FB") {this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) }}}})},//获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。getBLEDeviceCharacteristics(deviceId, serviceId) {console.info("蓝牙的deviceId====" + deviceId);console.info("蓝牙服务的serviceId====" + serviceId);wx.getBLEDeviceCharacteristics({deviceId,serviceId,success: (res) => {console.log('getBLEDeviceCharacteristics success', res.characteristics)for (let i = 0; i < res.characteristics.length; i++) {let item = res.characteristics[i]if (item.properties.read) {wx.readBLECharacteristicValue({deviceId,serviceId,characteristicId: item.uuid,})}if (item.properties.write) {this.setData({canWrite: true})this._deviceId = deviceIdthis._serviceId = serviceIdthis._characteristicId = item.uuidconsole.info("写入(第一步)的characteristicId====" + item.uuid);//初始化调用 写入信息的方法  1:代表开灯this.writeBLECharacteristicValue("1")}if (item.properties.notify || item.properties.indicate) {wx.notifyBLECharacteristicValueChange({deviceId,serviceId,characteristicId: item.uuid,state: true,})}}},fail(res) {console.error('getBLEDeviceCharacteristics', res)}})// 操作之前先监听,保证第一时间获取数据wx.onBLECharacteristicValueChange((characteristic) => {const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId)const data = {}if (idx === -1) {data[`chs[${this.data.chs.length}]`] = {uuid: characteristic.characteristicId,value: ab2hex(characteristic.value)}} else {data[`chs[${idx}]`] = {uuid: characteristic.characteristicId,value: ab2hex(characteristic.value)}}this.setData(data)})},/*** 写入的数据 格式转换* @param str* @returns 字符串 转 ArrayBuffer*/
hex2buffer(str) {console.info("写入的数据====" + str);//字符串 转 十六进制var val = "";for (var i = 0; i < str.length; i++) {if (val == "")val = str.charCodeAt(i).toString(16);elseval += "," + str.charCodeAt(i).toString(16);}//十六进制 转 ArrayBuffervar buffer = new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)})).buffer;return buffer;
},
//开灯
opendeng() {// 调用写入信息的方法 向蓝牙设备发送一个开灯的参数数据 ,  1:代表开灯var writeValue ="1";this.writeBLECharacteristicValue(writeValue)},
//关灯
guandeng() {// 调用写入信息的方法 向蓝牙设备发送一个关灯的参数数据 ,  0:代表关灯var writeValue ="0";this.writeBLECharacteristicValue(writeValue)},
writeBLECharacteristicValue(writeValue) {// 向蓝牙设备发送一个0x00的16进制数据// let buffer = new ArrayBuffer(1)// let dataView = new DataView(buffer)//  dataView.setUint8(0, 0)//调用hex2buffer()方法,转化成ArrayBuffer格式console.log('获取传递参数writeValue的数据为=====',writeValue)var buffer =this.hex2buffer(writeValue);console.log('获取二进制数据',buffer)//向低功耗蓝牙设备特征值中写入二进制数据。wx.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId,characteristicId: this._characteristicId,value: buffer,success (res) {console.log('成功写数据writeBLECharacteristicValue success', res)//如果 uni.writeBLECharacteristicValue 走 success ,证明你已经把数据向外成功发送了,但不代表设备一定就收到了。通常设备收到你发送过去的信息,会返回一条消息给你,而这个回调消息会在 uni.onBLECharacteristicValueChange 触发},fail(res) {console.error('失败写数据getBLEDeviceCharacteristics', res)}})
},
//断开与蓝牙低功耗设备的连接。closeBluetoothAdapter() {wx.closeBluetoothAdapter()this._discoveryStarted = false},
})

5.疑难点

1.如果你不确定写入的特性服务值可以通过(安卓)蓝牙助手获取特性值 deviceId(mac地址)、serviceId、characteristicId(苹果手机)蓝牙助手获得特性值deviceId(uuid地址)、serviceId、characteristicId  

注意:手机品类不同获取的deviceId的名称不同,但serviceId、characteristicId,是相同的

1.安卓手机(蓝牙助手获取的信息)
在这里插入图片描述
在这里插入图片描述

2.苹果手机(蓝牙助手)获取的信息

在这里插入图片描述
在这里插入图片描述

FFF0代表的serviceId全称:0000FFF0-0000-1000-8000-00805F9B34FB

FFF3代表的characteristicId全称:0000FFF3-0000-1000-8000-00805F9B34FB

最后:

祝愿你能一次成功
(代码直接复制粘贴到你的小程序中,替换下你自己设备的写入特性serviceId值),
就可以测试了
最后如果还满意,记得点下赞、收藏加关注、我也好回关,相互进步!!!!!!!!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十三章 SpringBoot项目(总)

1.创建SpringBoot项目 1.1.设置编码 1.4.导入已有的spring boot项目 2.快速搭建Restfull风格的项目 2.1.返回字符串 RestController public class IndexController {RequestMapping("/demo1")public Object demo1() {System.out.println("demo1 ran...."…

kafka的位移

文章目录 概要消费位移__consumer_offsets主题位移提交 概要 本文主要总结kafka的位移是如何管理的&#xff0c;在broker端如何通过命令行查看到位移信息&#xff0c;并从代码层面总结了位移的提交方式。 消费位移 对于 Kafka 中的分区而言&#xff0c;它的每条消息都有唯一…

0基础学习VR全景平台篇 第86篇:智慧眼-为什么要设置分组选择?

一、功能说明 分组选择&#xff0c;也就是给全景的每个分组去设置其所属的行政区划&#xff0c;设置后只有属于同行政区划的成员才可进入其场景进行相关操作&#xff0c;更便于实现城市的精细化管理。 二、后台编辑界面 分组名称&#xff1a;场景的分组名称。 对应分类&…

网络安全--linux下Nginx安装以及docker验证标签漏洞

目录 一、Nginx安装 二、docker验证标签漏洞 一、Nginx安装 1.首先创建Nginx的目录并进入&#xff1a; mkdir /soft && mkdir /soft/nginx/cd /soft/nginx/ 2.下载Nginx的安装包&#xff0c;可以通过FTP工具上传离线环境包&#xff0c;也可通过wget命令在线获取安装包…

【数据结构与算法】队列

文章目录 一&#xff1a;队列1.1 队列的概念1.2 队列的介绍1.3 队列示意图 二&#xff1a;数组模拟队列2.1 介绍2.2 思路2.3 代码实现2.3.1 定义队列基本信息2.3.2 初始化队列2.3.3 判断队列是否满&#xff0c;是否为空2.3.4 添加数据到队列2.3.5 获取队列数据&#xff0c;出队…

图数据库_Neo4j和SpringBoot整合使用_创建节点_删除节点_创建关系_使用CQL操作图谱---Neo4j图数据库工作笔记0009

首先需要引入依赖 springboot提供了一个spring data neo4j来操作 neo4j 可以看到它的架构 这个是下载下来的jar包来看看 有很多cypher对吧 可以看到就是通过封装的驱动来操作graph database 然后开始弄一下 首先添加依赖

【实用黑科技】如何 把b站的缓存视频弄到本地——数据恢复软件WinHex 和 音视频转码程序FFmpeg

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;效率…

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置相机的固定帧率(C#)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的固定帧率&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在BGAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过BGAPI SDK设置相机固定帧…

蓝牙资讯|中国智能家居前景广阔,蓝牙Mesh照明持续火爆

据俄罗斯卫星通讯社报道&#xff0c;中国已成为全球最大的智能家居消费国&#xff0c;占全球50%—60%的市场份额。未来&#xff0c;随着人工智能技术的发展以及智能家居生态的不断进步&#xff0c;智能家居在中国的渗透率将加速提升。德国斯塔蒂斯塔调查公司数据显示&#xff0…

win10系统docker创建ubuntu容器解决开发环境问题

一、win10系统使用docker的原因 最近啊&#xff0c;在学习人工智能-深度学习&#xff0c;用的win10系统进行开发&#xff0c;老是出现一些莫名其妙的问题&#xff0c;无法解决&#xff0c;每天都在为环境问题搞得伤透了脑筋。 说到底还是要使用Linux系统进行开发比较合适。 …

【MT32F006】MT32F006之HT1628驱动LED

本文最后修改时间&#xff1a;2023年03月30日 一、本节简介 本文介绍如何使用MT32F006连接HT1628芯片驱动LED。 二、实验平台 库版本&#xff1a;V1.0.0 编译软件&#xff1a;MDK5.37 硬件平台&#xff1a;MT32F006开发板&#xff08;主芯片MT32F006&#xff09; 仿真器&a…

LeetCode算法心得——限制条件下元素之间的最小绝对差(TreeSet)

大家好&#xff0c;我是晴天学长&#xff0c;今天用到了Java一个非常实用的类TreeSet&#xff0c;能解决一些看起来棘手的问题。 1 &#xff09;限制条件下元素之间的最小绝对差 2) .算法思路 初始化变量&#xff1a;n为列表nums的大小。 min为整型最大值&#xff0c;用于记录…

python3 0学习笔记之基本知识

0基础学习笔记之基础知识 &#x1f4da; 基础内容1. 条件语句 if - elif - else2. 错误铺捉try - except(一种保险策略&#xff09;3. 四种开发模式4. 函数&#xff1a;def用来定义函数的5. 最大值最小值函数&#xff0c;max &#xff0c;min6. is 严格的相等&#xff0c;is no…

机器学习:基本介绍

机器学习介绍 Hnad-crafted rules Hand-crafted rules&#xff0c;叫做人设定的规则。那假设今天要设计一个机器人&#xff0c;可以帮忙打开或关掉音乐&#xff0c;那做法可能是这样&#xff1a; 设立一条规则&#xff0c;就是写一段程序。如果输入的句子里面看到**“turn of…

C#__使用Type类反射数据的基本用法

// 简单介绍 // 元数据&#xff08;metadata&#xff09;&#xff1a;与程序及其类型有关的数据。 // 反射&#xff1a;一个运行的程序查看本身元数据或其他程序集中的元数据的行为 // Assembly类&#xff1a;允许访问给定程序集的元数据&#xff0c;包含了可以加载和执行程序…

【C# 基础精讲】文件读取和写入

文件读取和写入是计算机程序中常见的操作&#xff0c;用于从文件中读取数据或将数据写入文件。在C#中&#xff0c;使用System.IO命名空间中的类来进行文件读写操作。本文将详细介绍如何在C#中进行文件读取和写入&#xff0c;包括读取文本文件、写入文本文件、读取二进制文件和写…

选择大型语言模型自定义技术

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑器的3D应用场景 企业需要自定义模型来根据其特定用例和领域知识定制语言处理功能。自定义LLM使企业能够在特定的行业或组织环境中更高效&#xff0c;更准确地生成和理解文本。 自定义模型使企业能够创建符合其品牌…

BDA初级分析——认识SQL,认识基础语法

一、认识SQL SQL作为实用技能&#xff0c;热度高、应用广泛 在对数据分析人员的调查中SQL长期作为热度排名第-一的编程语言超过Python和R SQL&#xff1a;易学易用&#xff0c;高效强大的语言 SQL&#xff1a;Structured Query Language 结构化查询语言 SQL&#xff1a;易学…

多维时序 | MATLAB实现WOA-CNN-BiGRU-Attention多变量时间序列预测

多维时序 | MATLAB实现WOA-CNN-BiGRU-Attention多变量时间序列预测 目录 多维时序 | MATLAB实现WOA-CNN-BiGRU-Attention多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | MATLAB实现WOA-CNN-BiGRU-Attention多变量时间序列预测 1.程…

java 向上取整 java对小数取整

取整方法 Math.floor(double a) 向下取整 Math.ceil(double a) 向上取整 Math.round(double a) 四舍五入 0.5向下取整 Math.rint(double a) 就近取整 1.6接近2&#xff0c;所以就取2 1.4接近1&#xff0c;所以就取1 1.5跟1和2都很接近&#xff0c;这时候就取偶数 (int) 类型强转…