小程序蓝牙连接ESP32通信(可直接拿来用)

小程序中的蓝牙能力

在小程序中,要使用蓝牙能力(Beacon 除外)必须首先调用 wx.openBluetoothAdapter 初始化蓝牙适配器模块,其生效周期为调用 wx.openBluetoothAdapter 至调用 wx.closeBluetoothAdapter 或小程序被销毁为止。只有在小程序蓝牙适配器模块生效期间,开发者才能够正常调用蓝牙相关的小程序 API,并收到蓝牙模块相关的事件回调(绑定监听不受此限制)。

小程序对蓝牙支持情况如下:

经典蓝牙:iOS 因系统限制暂无法提供,安卓目前已在规划中。

蓝牙低功耗 (BLE):

  • 主机模式:基础库 1.1.0(微信客户端 iOS 6.5.6,Android 6.5.7)开始支持。
  • 从机模式:基础库 2.10.3 开始支持。
  • 蓝牙信标 (Beacon):基础库 1.2.0 开始支持。

前置条件

  • 蓝牙模块需要是 低功耗蓝牙(BLE) ,不然小程序搜索不到(将导致无法继续进行开发),可购买我们的设备 来进行开发。
  • 开发者工具上只能模拟部分蓝牙接口能力,完整功能请使用真机调试。

官方文档

微信小程序蓝牙开发文档

微信小程序提供的操作蓝牙的 API

微信小程序目前有蓝牙 API 共 18 个

操作蓝牙适配器的 API
wx.openBluetoothAdapter 初始化蓝牙适配器
wx.closeBluetoothAdapter 关闭蓝牙模块
wx.getBluetoothAdapterState 获取本机蓝牙适配器状态
wx.onBluetoothAdapterStateChange 监听蓝牙适配器状态变化事件
连接前使用的 API
wx.startBluetoothDevicesDiscovery 开始搜寻附近的蓝牙外围设备
wx.stopBluetoothDevicesDiscovery 停止搜寻附近的蓝牙外围设备
wx.getBluetoothDevices 获取所有已发现的蓝牙设备
wx.onBluetoothDeviceFound 监听寻找到新设备的事件
连接和断开时使用的 API
wx.createBLEConnection 连接低功耗蓝牙设备
wx.closeBLEConnection 断开与低功耗蓝牙设备的连接
连接成功后使用的 API
wx.getConnectedBluetoothDevices 根据 uuid 获取处于已连接状态的设备
wx.getBLEDeviceServices 获取蓝牙设备所有 service(服务)
wx.getBLEDeviceCharacteristics  获取蓝牙设备所有 characteristic(特征值)
wx.readBLECharacteristicValue  读取低功耗蓝牙设备的特征值的二进制数据值
wx.writeBLECharacteristicValue 向低功耗蓝牙设备特征值中写入二进制数据
wx.notifyBLECharacteristicValueChange  启用低功耗蓝牙设备特征值变化时的 notify 功能
wx.onBLECharacteristicValueChange 监听低功耗蓝牙设备的特征值变化
wx.onBLEConnectionStateChange 监听低功耗蓝牙连接的错误事件

基本操作流程

最基本的操作流程是:初始化蓝牙适配器 → 开始搜寻附近的蓝牙外围设备 → 监听寻找到新设备的事件 → 连接低功耗蓝牙设备 → 获取蓝牙设备所有 service 和 characteristic → 读取或写入低功耗蓝牙设备的特征值的二进制数据值。

蓝牙组件代码

由于我们 index 中代码量比较多,不利于维护,所以我们将蓝牙功能单独抽离成一个 component(组件),方便管理和复用。

新建组件

新建一个 components 目录,在该目录下新建一个目录为 bluetooth-comp,然后在 bluetooth-comp 点击"新建 Component"按钮,输入 index 并点击确定。

页面结构部分
<!-- bluetooth-comp/index.wxml -->
<view style="margin: 26rpx"><button wx:if="{{!connected}}" bindtap="openBluetoothAdapter">开始扫描</button><button wx:else bindtap="closeBLEConnection">断开连接 - {{name}}</button><view class="devices_summary">已发现 {{devices.length}} 个外围设备:</view><viewwx: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</view><view style="font-size: 10px">UUID: {{item.deviceId}}</view></view>
</view>
样式部分
/* bluetooth-comp/index.wxss */
.devices_summary {margin-top: 30px;padding: 10px;font-size: 16px;
}.device_item {border-bottom: 1px solid #eee;padding: 10px;color: #666;
}
.device_item_hover {background-color: rgba(0, 0, 0, 0.1);
}
逻辑部分

在 data 中定义变量

// bluetooth-comp/index.js
data:{devices: [],connected: false,chs: []
}

js 文件顶部定义工具方法

function inArray(arr, key, val) {for (let i = 0; i < arr.length; i++) {if (arr[i][key] === val) {return i;}}return -1;
}// 将字符串转为 ArrayBuffer
function str2ab(str) {let buf = new ArrayBuffer(str.length);let bufView = new Uint8Array(buf);for (var i = 0, strLen = str.length; i < strLen; i++) {bufView[i] = str.charCodeAt(i);}return buf;
}

在 methods 中定义方法

// bluetooth-comp/index.js
methods: {/* 初始化蓝牙模块 */openBluetoothAdapter() {// 先关闭蓝牙模块再开启 防止断开后点连接连接不上this.closeBluetoothAdapter();wx.openBluetoothAdapter({success: response => {console.log("初始化蓝牙模块成功:openBluetoothAdapter", response);this.startBluetoothDevicesDiscovery();},fail: err => {if (err.errCode === 10001) {/* 监听蓝牙适配器状态变化事件 */wx.onBluetoothAdapterStateChange(res => {console.log("监听蓝牙适配器状态变化事件:onBluetoothAdapterStateChange", res);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 = true;wx.startBluetoothDevicesDiscovery({allowDuplicatesKey: true,success: response => {console.log("开始搜寻附近的蓝牙外围设备:startBluetoothDevicesDiscovery", response);this.onBluetoothDeviceFound();},fail: err => {console.log("搜索设备失败", err);wx.showToast({ title: "搜索设备失败", icon: "none" });},});},/* 停止搜寻附近的蓝牙外围设备。*/stopBluetoothDevicesDiscovery() {console.log("停止搜寻附近的蓝牙外围设备");wx.stopBluetoothDevicesDiscovery();},/* 监听搜索到新设备的事件 */onBluetoothDeviceFound() {wx.onBluetoothDeviceFound(res => {res.devices.forEach(device => {if (!device.name && !device.localName) {return;}const foundDevices = this.data.devices;const 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.dataset;const deviceId = ds.deviceId;const name = ds.name;wx.createBLEConnection({deviceId,success: () => {this.setData({ connected: true, name, deviceId });wx.showToast({ title: "连接蓝牙设备成功", icon: "none" });this.getBLEDeviceServices(deviceId);},fail: e => {console.log("连接失败", e.errMsg);wx.showToast({ title: "连接失败,错误信息: " + e.errMsg, icon: "none" });},});// 停止搜寻蓝牙设备this.stopBluetoothDevicesDiscovery();},/* 断开与蓝牙低功耗设备的连接。 */closeBLEConnection() {console.log("断开与蓝牙低功耗设备的连接");wx.showToast({ title: "已断开和蓝牙设备的连接", icon: "none" });wx.closeBLEConnection({ deviceId: this.data.deviceId });this.setData({ connected: false, chs: [], canWrite: false });},/* 获取蓝牙低功耗设备所有服务 (service) */getBLEDeviceServices(deviceId) {wx.getBLEDeviceServices({deviceId,success: res => {for (let i = 0; i < res.services.length; i++) {if (res.services[i].isPrimary) {this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid);return;}}},});},/* 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 */getBLEDeviceCharacteristics(deviceId, serviceId) {wx.getBLEDeviceCharacteristics({deviceId,serviceId,success: res => {console.log("获取蓝牙低功耗设备某个服务中所有特征:getBLEDeviceCharacteristics");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 = deviceId;this._serviceId = serviceId;this._characteristicId = item.uuid;//   this.writeBLECharacteristicValue();}if (item.properties.notify || item.properties.indicate) {wx.notifyBLECharacteristicValueChange({deviceId,serviceId,characteristicId: item.uuid,state: true,success(res) {console.log("notifyBLECharacteristicValueChange success", res);},});}}},fail(res) {console.error("getBLEDeviceCharacteristics", res);},});// 操作之前先监听,保证第一时间获取数据wx.onBLECharacteristicValueChange(characteristic => {// TODO 收到的信息为ArrayBuffer类型,可根据自己的需要转换 可发送给父组件用来回显console.log("收到原始的数据", characteristic, characteristic.value);// 测试向设备发送数据// this.writeBLECharacteristicValue(JSON.stringify({"FAN":"OFF"}))});},/* 向蓝牙低功耗设备特征值中写入二进制数据 */writeBLECharacteristicValue(jsonStr) {let arrayBufferValue = str2ab(jsonStr);console.log("发送数据给蓝牙", "原始字符串", jsonStr, "转换arrayBuffer", arrayBufferValue);wx.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId, // 微信文档上是错误的characteristicId: this._characteristicId,value: arrayBufferValue, // 只能发送arrayBuffer类型数据success(res) {console.log("消息发送成功", res.errMsg);wx.showToast({ title: "消息发送成功", icon: "none" });},fail(e) {console.log("发送消息失败", e);wx.showToast({ title: "发送消息失败,错误信息: " + e.errMsg, icon: "none" });},});},closeBluetoothAdapter() {console.log("关闭蓝牙模块");wx.closeBluetoothAdapter();this._discoveryStarted = false;},
};

最终效果

界面

界面

真机调试结果

真机调试结果


嵌入式物联网教学开发 传感器控制拓展板二合一

不同于其他卖家提供资料和技术支持,我们提供手把手教学,完整的开发流程如下:

实现完整的一个物联网嵌入式项目:将数据上传并通过小程序对硬件进行控制。具体有:

[1]服务器配置,阿里云搭建mqttx服务器,ssl证书配置;

[2]微信小程序设计,借助微信开发者工具开发,js代码和类html语言;

[3]硬件驱动,基于Arduino平台开发esp32,提供wifi和蓝牙版本,读取传感器:温度、湿度、烟雾;控制设备:小灯、继电器。

提供教学视频在b站,合集播放破6w!提供项目开发文档,网页链接。

我们提供搭建好的mqtt测试服务器,供大家免费使用。

适合如下人群:

1.喜欢diy的电子极客;

2.物联网专业的相关学生课程或毕业设计;

3.寻求物联网项目经验的求职者;

有硬件工程师和软件工程师答疑,欢迎咨询~

文档资料,可参考:基于ESP32+微信小程序的物联网应用开发文档

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

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

相关文章

评价决策类-层次分析法

师从江北 问题引出 归一化处理&#xff1a;指标的数组[a b c]归一化处理得到[a/(abc),b/(abc),c/(abc)] 因为每个指标的重要性不同&#xff0c;所以要加上一个权重 如何科学的确定权重&#xff0c;就要用到层次分析法&#xff08;AHP&#xff09; 模型原理 建立递阶层次结构模…

VMware17虚拟机安装Kali Linux2024详解

目录 简介 一、环境搭建 二、下载ISO镜像 三、新建虚拟机 为虚拟机选择合适的操作系统类型和版本 分配适当的内存、硬盘空间和其他虚拟机配置选项 四、硬件配置 编辑虚拟机设置 选择安装介质 五、界面化安装配置 简介 Kali Linux是一个基于Debian的Linux发行版&#…

【记录】docker笔记(五):Docker网络-Network Namespace

Docker 网络理论基础 要了解docker网络&#xff0c;先了解如下基础概念。 Network Namespace Docker 网络的底层原理是 Linux 的 Network Namespace &#xff0c;所以对于 Linux Network Namespace 的理解对 Docker 网络底层原理的理解非常重要。 简介 Network Name…

【董晓算法】动态规划之线性DP问题

前言&#xff1a; 本系列是看的B站董晓老师所讲的知识点做的笔记 董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com) 树塔-记忆化搜索 特点&#xff08;前提&#xff09;&#xff1a;从上向下的累加和是不能重复使用的&#xff0c;从下向上的累加和是可以重…

C++进阶:哈希(2)位图与布隆过滤器

目录 1. 位图&#xff08;bitset&#xff09;1.1 引子&#xff1a;海量整形数据的处理1.2 结构描述1.3 位图实现1.4 位图相关题目练习 2. 布隆过滤器&#xff08;BloomFilter&#xff09;2.1 引子&#xff1a;海量非int类型数据处理&#xff08;string&#xff09;2.2 结构描述…

文心一言 VS 讯飞星火 VS chatgpt (252)-- 算法导论18.2 5题

五、因为叶结点无需指向孩子结点的指针&#xff0c;那么对同样大小的磁盘页面&#xff0c;可选用一个与内部结点不同的(更大的) t 值。请说明如何修改 B 树的创建和插人过程来处理这个变化。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 当我们在B树&#xff…

搭载全新升级viaim AI,讯飞会议耳机Pro 2首销价1399元起

2024年5月15日&#xff0c;人工智能硬件公司未来智能发布了讯飞会议耳机Pro 2、iFLYBUDS 2以及Kit 2三款旗舰新品&#xff0c;为用户带来全新升级的viaim AI&#xff0c;也为AIGC智能耳机树立了新标杆。 在发布会上&#xff0c;未来智能CEO马啸表示&#xff1a;在AIGC领域&…

【C++ 高阶数据结构 Test】AVL ~ 二叉搜索树

文章目录 1. AVL 树概念2. AVL 树节点的定义3. AVL树的插入4. AVL树的旋转4.1 新节点插入较高左子树的左侧---左左&#xff1a;右单旋4.2 新节点插入较高右子树的右侧---右右&#xff1a;左单旋4.3 新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋4.4 新节点插…

【JAVA入门】Day05 - 面向对象

【JAVA入门】Day05 - 面向对象 文章目录 【JAVA入门】Day05 - 面向对象一、对象的设计和使用1.1 类和对象1.2 类的分类 二、封装三、private 关键字四、this 关键字五、构造方法六、JavaBean七、对象的内存图7.1 一个对象的内存图7.2 两个对象的内存图7.3 两个引用指向同一个对…

【练习】分治--快排思想

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;算法(Java)&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 颜色分类 题目描述 题解 代码实现 排序数组 题目描述 题解 代码…

战网国际服下载教程 暴雪战网客户端一键下载安装教程分享

战网国际服务平台&#xff0c;又名Battle.net环球版&#xff0c;是暴雪娱乐操作的跨国界游戏交流平台&#xff0c;它消除了地域的隔阂&#xff0c;向全球范围内的游戏爱好者提供服务。与仅服务于特定地区的版本不同&#xff0c;国际版赋予了玩家自由穿梭于暴雪众多标志性游戏的…

ubuntu中如何删除常规匹配不到的乱码目录文件

原因是之前误操作创建了多个带空格的gerrit仓库的时候导致的服务器乱码&#xff0c;进入geriit服务器可以查看到如下的一个异常目录&#xff0c;常规rm -rf 操作的时候是匹配不到这个目录的。 这时候我们应该考虑使用inode的性质来匹配删除。 注&#xff1a;在Linux文件系统中…

数论专题练习

质数专题 我的思路就是一个素数筛&#xff0c;然后双指针 class Solution { public:int maximumPrimeDifference(vector<int>& nums) {unordered_map<int, int> mp;for (int i 2; i < 100; i) {if (mp[i] 0) {for (int j 2 * i; j < 100; j i) {mp[…

失业焦虑如何缓解心情?流静冥想

失业焦虑如何缓解心情&#xff1f;人生旅途&#xff0c;失业犹如山重水复&#xff0c;焦虑似迷雾遮望眼。古语云&#xff1a;“山不厌高&#xff0c;海不厌深。”心之向往&#xff0c;冥想便是那披荆斩棘之斧&#xff0c;如何带你走出困境&#xff1f; “静以修身”&#xff0c…

Python使用asyncio包实现异步编程

1. 异步编程 异步编程是一种编程范式&#xff0c;用于处理程序中需要等待异步操作完成后才能继续执行的情况。异步编程允许程序在执行耗时的操作时不被阻塞&#xff0c;而是在等待操作完成时继续执行其他任务。这对于处理诸如文件 I/O、网络请求、定时器等需要等待的操作非常有…

RALL-E: Robust Codec Language Modeling with Chain-of-Thought Prompting for TTS

demo pageDetai Xin&#xff0c; tanxu微软 & 东大 & 浙大 abstract 使用CoT的思路&#xff0c;和Valle的框架&#xff0c;先实现LLM预测音素级别pitch/duration&#xff0c;然后预测speech token。 methods Prosody tokens as chain-of-thought prompts 和Valle一…

6. 网络编程-网络io与select、poll,epoll

https://0voice.com/uiwebsite/html/courses/v13.7.html 首先看看这个学习计划 网络、网络编程、网络原理基础组件&#xff0c;20个。中间件 Redis ,MySQL&#xff0c;Kafka&#xff0c;RPC&#xff0c;Nginx开源框架&#xff08;解决方案&#xff09;业务开发(工程师开发&am…

(1)双指针算法介绍与练习:移动零

目录 双指针算法介绍 练习&#xff1a;移动零 双指针算法介绍 双指针算法常见于数组和双向链表的题型 在数组中&#xff0c;双指针中的指针代表数组元素的下标&#xff0c;而不是真正的指针类型变量 在双向链表中&#xff0c;双指针中的指针即为真正意义上的指针&#xff…

CCF PTA 2022年11月C++学生会提名

【问题描述】 学生会选举要开始了。根据选举规则&#xff0c;首先由全体同学进行提名&#xff0c;每位同学可以从全体同学中提 名一名同学参选。选举时&#xff0c;会从全体同学的提名中选出一名学生会主席&#xff0c;再从三个年级分别的提名中 各选出一名副主席。现在&#…

【数据结构】堆(超详细)

文章目录 前言堆的概念及结构堆的实现堆的向下调整算法&#xff08;建小堆为例&#xff09;堆的向上调整算法&#xff08;建小堆为例&#xff09;堆的初始化销毁堆堆的插入堆的删除(规定删堆顶的数据)取堆顶元素判断堆是否为空获取堆的个数 完整代码&#xff08;包括测试代码&a…