当前位置: 首页 > news >正文

微信小程序 蓝牙通讯

客户的需求如下:通过微信小程序控制蓝牙ble设备(电子面膜),通过不同指令控制面膜的亮度和时间。

01.首先看下客户的ble设备服务文档:(本部分需要有点蓝牙基础,在调试过程中可以用安卓软件nRF Connect软件来执行测试命令)
在这里插入图片描述
0xFFF1灯控命令
命令格式:

在这里插入图片描述
命令类型:

0x01 – 常规模式,命令数据第一个字节为模式(1-3表示模式1-3),第二个字节为开关状态(0为暂停,1为启动)。

0x02 – 个性模式,命令数据第一个数据为强度百分比(1-100),第二个字节是时间低位,第三个字节是时间高位(单位秒)。

FFF2 灯状态
4个字节,数据同灯控命令的(命令类型+命令数据)。

FFF3验证码算法
通道用户连接时加密验证,该通道具有read/write 两种属性。

以下是手机端连接上设备后的加密流程。

手机连接SKLight(记录MAC地址) => 使能SKLight FFF2通道完成 => 读取(read) FFF3 新生成的4个字节的随机数 => 随机数结合设备的MAC地址计算出验证码=> FFF3 将验证码写给 SKLight (建议发3次) 读取验证结果(建议500-1000ms后读取,这时只有0x01一个字节正确,0x00则为失败)=>完成(失败请APP断开连接)

计算验证码的 C 函数:

// mac 为设备MAC地址 , rand为读到的随机数// auth_data 为计算得到的验证码,2个字节void getAuthenticationData(uint8_t *mac, uint8_t *rand,uint8_t *auth_data){auth_data [0] = mac[0]^ mac [1]^mac[2]^rand[0]^rand[1];auth_data [1] = mac[3]^mac[4]^mac[5]^rand[2]^rand[3];}

FFF4 电池状态
6个字节,字节1为电池电压高8位,字节2为电池电压低8位;字节3为电池电流高8位,字节4为电池电流低8位;字节5为电池电量(1-5),1表示低电量,5表示满电量;字节6为工作计时,为0时表示负载开路。

FFF8修改密码
验证成功后,可以通过该通道进行修改密码:

密码应为字符格式。

数据格式:共12字节:
在这里插入图片描述
修改密码应该在 500~1000ms 以后读取该通道,读到0x01 说明密码修改成功,否则失败。

FFF9修改设备名称
验证成功后,可以通过该通道进行修改设备广播名称:

数据格式:1~20字节:
修改密码应该在 500~1000ms 以后读取该通道,读到0x01 说明名称修改成功,否则失败。

名称修改完成后于断开连接时生效广播。

02.现在开始进行开发小程序端:

0201.蓝牙适配器开启

wx.openBluetoothAdapter({success: function (res) {//开启成功,继续搜索操作},fail:function(){//开启失败,后台监听状态处理,注意:在安卓系统中手动开启蓝牙可以监听,苹果在设置中开启监听不到,必须使用快捷图标开启(算是小程序蓝牙之坑)wx.onBluetoothAdapterStateChange(function (res) {if (res.available) {//后台监听到蓝牙适配器的状态变化,并且可用.}})       }
})

0202.搜索设备

//单纯的去搜索设备,并不会返回搜索列表
wx.startBluetoothDevicesDiscovery({success: function (res) {//已经执行搜索,查看搜索到的设备列表wx.getBluetoothDevices({success: function (res) {//打印获取到的设备列表,此处可以获取到设备的广播消息//设备的deviceId字段要非常注意,安卓返回的硬件mac地址,苹果返回的是uuid//当然无论返回什么都不影响你使用小程序蓝牙api//但是如果你的服务uuid需要你提供硬件mac地址交互的话需要做兼容处理//例如你可以要求蓝牙方在广播数据中保存硬件mac地址.(第2坑)console.log(res)}})    }
})

0203.连接ble设备

wx.createBLEConnection({//这里的deviceId就是上一步获取的设备列表的deviceId属性,不用关心这个字段的值,不关心是安卓还是苹果deviceId: deviceId,success: function (res) {console.log(res)}
})

0204.获得验证码

//上面的文档指示我通过FFF3服务uuid读取1个4位数字的验证码
//然后结合设备硬件mac地址通过C算法生成验证码发送给设备//002.读取后我拿来计算
wx.onBLECharacteristicValueChange(function (characteristic) {var macstring = deviceId;//设备mac地址,我处理过.不能直接用搜索列表的deviceIdvar randstring = ab2hex(characteristic.value);//设备给我的4位数字var verifycode = getAuthenticationData(macstring, randstring);//需要将C语言的算法转javascript})
//001.我来读取4位数字
wx.readBLECharacteristicValue({deviceId: deviceId,serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',characteristicId: '0000FFF3-0000-1000-8000-00805F9B34FB',success: function (res) {}
})//003.C语法转换的javascript
function getAuthenticationData(macstring, randstring) {var auth_data = new Array();//Macvar Tempmac = macstring.split(':');for (var i = 0; i < Tempmac.length; i++) {Tempmac[i] = '0x' + Tempmac[i];}var mac = new Uint8Array(Tempmac);//Mac-End//Randvar Temprand = new Array();var temprandj = 0;for (var i = 0; i < randstring.length; i++) {Temprand[temprandj] = '0x' + randstring.slice(i, i + 2);i++;temprandj++;}var rand = new Uint8Array(Temprand);//Rand-Endauth_data[0] = mac[0] ^ mac[1] ^ mac[2] ^ rand[0] ^ rand[1];auth_data[1] = mac[3] ^ mac[4] ^ mac[5] ^ rand[2] ^ rand[3];auth_data[0] = auth_data[0].toString(16);auth_data[1] = auth_data[1].toString(16);return auth_data;
}

0205.发送验证码

  sendverify(verifycode);//发送验证码。文档建议发送3次然后再读取值,如果值是1那么验证通过,其他的uuid指令也通过验证sendverify: function (verifycode) {var self = this;var deviceId =app.globalData.deviceId;for (var i = 0; i < 3; i++) {var hex =verifycode[0] + verifycode[1];var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)}))//console.log('本次执行命令:' + hex);var buffer = typedArray.bufferwx.writeBLECharacteristicValue({deviceId: deviceId,serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',characteristicId: '0000FFF3-0000-1000-8000-00805F9B34FB',value: buffer,success: function (res) {//console.log('writeBLECharacteristicValue success', res.errMsg)}})}//文档建议1000MS后读取验证码setTimeout(function () {wx.onBLECharacteristicValueChange(function (characteristic) {var rescode = parseInt(ab2hex(characteristic.value),10);if (rescode ==1) {//console.log('通过验证');wx.notifyBLECharacteristicValueChange({state: true, deviceId: deviceId,serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',characteristicId: '0000FFF4-0000-1000-8000-00805F9B34FB',success: function (res) {//读取电量信息wx.onBLECharacteristicValueChange(function (res) {var charge = ab2hex(res.value);console.log('原始数据:'+charge);app.globalData.bettery=parseInt('0x' + charge[8] + charge[9], 16);app.globalData.blecurrent = parseInt('' + charge[4] + charge[5] + charge[6] + charge[7]+'', 16)var dianya = parseInt('' + charge[0] + charge[1] + charge[2] + charge[3] + '', 16)console.log('电压:' + dianya);console.log('电量:' + app.globalData.bettery);console.log('电流:' + app.globalData.blecurrent);                  })//读取电量信息}})   return;                  }else {//验证码验证失败self.setData({ishow:0,showstatus: { text: 'Err,请尝试重新连接!', status: 1 }}); wx.closeBLEConnection({deviceId: deviceId})                            }})wx.readBLECharacteristicValue({deviceId: deviceId,serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',characteristicId: '0000FFF3-0000-1000-8000-00805F9B34FB',success: function (res) {}})}, 1000)},

0206.灯控测试,常规模式3启动

//指令构造要注意高位和低位的处理
var hex = 'fa010301000c22'var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
}))
var buffer = typedArray.buffer
//指令构造
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
characteristicId: '0000FFF1-0000-1000-8000-00805F9B34FB',
value: buffer,
success: function (res) {
//console.log('writeBLECharacteristicValue success', res.errMsg)
}
})

相关文章:

微信小程序 蓝牙通讯

客户的需求如下&#xff1a;通过微信小程序控制蓝牙ble设备(电子面膜)&#xff0c;通过不同指令控制面膜的亮度和时间。 01.首先看下客户的ble设备服务文档&#xff1a;(本部分需要有点蓝牙基础,在调试过程中可以用安卓软件nRF Connect软件来执行测试命令) 0xFFF1灯控命令 命…...

java后端项目技术记录

后端使用技术记录 一、软件1. apifox&#xff0c;API管理软件问题 2. nginx前端服务器(1) 反向代理(2) 负载均衡 二、问题1. 使用spring全局异常处理器处理特定的异常2. 扩展springmvc的消息转换器&#xff08;对象和json数据的转换&#xff09;3. 路径参数的接收4. 实体构建器…...

PostgreSQL数据库与PostGIS在Windows中的部署与运行

本文介绍在Windows电脑中&#xff0c;下载、安装、部署并运行PostgreSQL与PostGIS数据库服务的方法。 PostgreSQL是一种功能强大的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;以其稳定性、可靠性和丰富的功能而闻名&#xff1b;其支持多种高级特性&…...

高级算法设计与分析 学习笔记10 平摊分析

动态表&#xff0c;可以变长。 一溢出就另起一个两倍大小的表。 可以轻易证明把n个数字放进去的时间复杂度是O(n)&#xff0c;n n/2 n/4……也就2n&#xff0c;插入数字本身也就是n&#xff0c;加起来最多不超过3n. 这种复杂度究竟是怎么算的&#xff1f;毕竟每次插入复杂度…...

从“纸面算力”到“好用算力”,超聚变打通AI+“最后一公里”

如果要评选2024年的年度科技名词&#xff0c;AI当属最热门的候选项。 年初的《政府工作报告》中首次提出了“人工智能”行动&#xff0c;正在从顶层设计着手&#xff0c;加快形成以人工智能为引擎的新质生产力。 折射到市场层面&#xff0c;AI作为一种新的范式&#xff0c;不…...

【有啥问啥】具身智能(Embodied AI):人工智能的新前沿

具身智能&#xff08;Embodied AI&#xff09;&#xff1a;人工智能的新前沿 引言 在人工智能&#xff08;AI&#xff09;的进程中&#xff0c;具身智能&#xff08;Embodied AI&#xff09;正逐渐成为研究与应用的焦点。具身智能不仅关注于机器的计算能力&#xff0c;更强调…...

11-pg内核之锁管理器(六)死锁检测

概念 每个事务都在等待集合中的另一事务&#xff0c;由于这个集合是一个有限集合&#xff0c;因此一旦在这个等待的链条上产生了环&#xff0c;就会产生死锁。自旋锁和轻量锁属于系统锁&#xff0c;他们目前没有死锁检测机制&#xff0c;只能靠内核开发人员在开发过程中谨慎的…...

Git 与标签管理

在 Git 中&#xff0c;标签 tag 是指向某个 commit 的指针&#xff08;所以创建和删除都很快&#xff09;。Git 有 commit id 了&#xff0c;为什么还要有 tag&#xff1f;commit id 是一串无规律的数字&#xff0c;不好记&#xff1b;而 tag 是我们自定义的&#xff0c;例如我…...

【0334】Postgres内核之 auxiliary process(辅助进程)初始化 MyPgXact

1. MyPgXact(ProcGlobal->allPgXact)间接初始化 在上一篇文章【0333】Postgres内核之 auxiliary process(辅助进程)创建 PGPROC 中, 讲解了Postgres内核完成 AuxiliaryProcess 初始化 pid、lxid、procLatch、myProcLocks、lockGroupMembers等所有成员的过程。 这些成员…...

20.1 分析pull模型在k8s中的应用,对比push模型

本节重点介绍 : push模型和pull模型监控系统对比为什么在k8s中只能用pull模型的k8s中主要组件的暴露地址说明 push模型和pull模型监控系统 对比下两种系统采用的不同采集模型&#xff0c;即push型采集和pull型采集。不同的模型在性能的考虑上是截然不同的。下面表格简单的说…...

Ubuntu 镜像替换为阿里云镜像:简化你的下载体验

Ubuntu&#xff0c;作为一款广受欢迎的Linux发行版&#xff0c;以其稳定性和易用性著称。但你是否曾因为下载速度慢而感到沮丧&#xff1f;现在&#xff0c;你可以通过将Ubuntu的默认下载源替换为阿里云镜像来解决这个问题。本文将指导你如何完成这一过程。 为什么选择阿里云镜…...

The Sandbox 游戏制作教程第 6 章|如何使用装备制作出色的游戏 —— 避免环境危险

欢迎回到我们的系列&#xff0c;我们将记录 The Sandbox Game Maker 的 “On-Equip”&#xff08;装备&#xff09;功能的多种用途。 如果你刚加入 The Sandbox&#xff0c;装备功能是 “可收集组件”&#xff08;Collectable Component&#xff09;中的一个多功能工具&#xf…...

JavaScript中的输出方式

1. console.log() console.log() 是开发者在调试代码时最常用的方法。它将信息打印到浏览器的控制台&#xff0c;使开发者能够查看变量的值、程序的执行状态以及其他有用的信息。 用途&#xff1a;用于调试和记录程序运行时的信息。优点&#xff1a;简单易用&#xff0c;适合…...

力扣9.25

2306. 公司命名 给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下&#xff1a; 从 ideas 中选择 2 个 不同 名字&#xff0c;称为 ideaA 和 ideaB 。 交换 ideaA 和 ideaB 的首字母。 如果得到的两个新名字 都 不在ideas 中&#xff0c;那么 …...

从零开始之AI面试小程序

从零开始之AI面试小程序 文章目录 从零开始之AI面试小程序前言一、工具列表二、开发部署流程1. VMWare安装2. Centos安装3. Centos环境配置3.1. 更改子网IP3.2. 配置静态IP地址 4. Docker和Docker Compose安装5. Docker镜像加速源配置6. 部署中间件6.1. MySQL部署6.2. Redis部署…...

Html2OpenXml:HTML转化为OpenXml的.Net库,轻松实现Html转为Word。

推荐一个开源库&#xff0c;轻松实现HTML转化为OpenXml。 01 项目简介 Html2OpenXml 是一个开源.Net库&#xff0c;旨在将简单或复杂的HTML内容转换为OpenXml组件。 该项目始于2009年&#xff0c;最初是为了将用户评论转换为Word文档而设计的 随着时间的推移&#xff0c;Ht…...

HumanNeRF:Free-viewpoint Rendering of Moving People from Monocular Video 精读

1. 姿态估计和骨架变换模块 人体姿态估计&#xff1a;HumanNeRF 通过已知的单目视频对视频中人物的姿态进行估计。常见的方法是通过人体姿态估计器&#xff08;如 OpenPose 或 SMPL 模型&#xff09;提取人物的骨架信息&#xff0c;获取 3D 关节的位置信息。这些关节信息可以帮…...

Springboot中基于注解实现公共字段自动填充

1.使用场景 当我们有大量的表需要管理公共字段&#xff0c;并且希望提高开发效率和确保数据一致性时&#xff0c;使用这种自动填充方式是很有必要的。它可以达到一下作用 统一管理数据库表中的公共字段&#xff1a;如创建时间、修改时间、创建人ID、修改人ID等&#xff0c;这些…...

Android 已经过时的方法用什么新方法替代?

过时修正举例 (Kotlin): getColor(): resources.getColor(R.color.white) //已过时// 修正后:ContextCompat.getColor(this, R.color.white) getDrawable(): resources.getDrawable(R.mipmap.test) //已过时//修正后:ContextCompat.getDrawable(this, R.mipmap.test) //…...

【RocketMQ】MQ与RocketMQ介绍

&#x1f3af; 导读&#xff1a;本文介绍了消息队列&#xff08;MQ&#xff09;的基本概念及其在分布式系统中的作用&#xff0c;包括实现异步通信、削峰限流和应用解耦等方面的优势&#xff0c;并对ActiveMQ、RabbitMQ、RocketMQ及Kafka四种MQ产品进行了对比分析&#xff0c;涵…...

GTX 1660实战AI视频生成:低显存环境下的模型瘦身与帧插值方案

1. 项目概述&#xff1a;在入门级显卡上跑通AI视频生成最近看到不少朋友对AI视频生成很感兴趣&#xff0c;但总被“需要RTX 4090”、“至少24GB显存”这类硬件门槛劝退。作为一个常年混迹于“丐版”硬件圈的老玩家&#xff0c;我决定用我手头这块服役多年的GTX 1660&#xff08…...

喜马拉雅VIP音频下载指南:xmly-downloader-qt5完整解决方案

喜马拉雅VIP音频下载指南&#xff1a;xmly-downloader-qt5完整解决方案 【免费下载链接】xmly-downloader-qt5 喜马拉雅FM专辑下载器. 支持VIP与付费专辑. 使用GoQt5编写(Not Qt Binding). 项目地址: https://gitcode.com/gh_mirrors/xm/xmly-downloader-qt5 你是否曾为…...

告别硬编码!SAP ABAPer必学的5个POPUP函数实战用法(附完整代码)

告别硬编码&#xff01;SAP ABAPer必学的5个POPUP函数实战用法&#xff08;附完整代码&#xff09; 在SAP ABAP开发中&#xff0c;交互设计往往决定了用户体验的好坏。想象一下这样的场景&#xff1a;用户在执行关键操作时缺乏明确确认&#xff0c;导致数据误删&#xff1b;或者…...

Web技术为何称王?五大核心优势碾压原生应用,一文读懂现代Web的统治力

本文深入剖析Web技术&#xff08;涵盖H5、PWA及现代Web App&#xff09;相对于原生APP的五大核心优势&#xff1a;跨平台低成本、免安装热更新、无缝分发能力、技术生态与标准演进、AI融合前景。通过详实的数据对比与技术架构拆解&#xff0c;揭示为什么Web依然是数字世界的终极…...

从用户态到内核态:Linux Hook技术的全景实践与攻防解析

1. Linux Hook技术入门&#xff1a;从概念到实践 第一次接触Hook技术是在十年前的一个安全分析项目中&#xff0c;当时需要监控某个可疑进程的行为。那时候我才明白&#xff0c;原来Linux系统里藏着这么多可以"截胡"程序执行的秘密通道。简单来说&#xff0c;Hook技术…...

在OpenClaw项目中配置Taotoken作为Agent的模型供应商

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 在OpenClaw项目中配置Taotoken作为Agent的模型供应商 基础教程类&#xff0c;指导在虚拟机环境使用OpenClaw框架开发AI Agent的用户…...

告别手动刷新!用PowerShell脚本实现Windows下校园网自动重连(含任务计划设置)

告别手动刷新&#xff01;用PowerShell脚本实现Windows下校园网自动重连&#xff08;含任务计划设置&#xff09; 每次开机都要手动登录校园网&#xff1f;网络突然断开还得重新输入账号密码&#xff1f;这些繁琐操作已经成为过去式。本文将手把手教你用PowerShell打造全自动校…...

自动化测试系统开关架构与继电器选型指南

1. 自动化测试系统中的开关架构选择在自动化测试系统中&#xff0c;开关架构的选择直接影响着测试效率、信号完整性和系统成本。根据测试需求和被测设备(DUT)特性&#xff0c;我们可以将开关架构分为四种基本类型。1.1 无开关架构无开关架构是最直接的连接方式&#xff0c;每个…...

使用 LikeShop 搭建商城的完整流程(从0到上线)

先说结论用 LikeShop 搭建商城&#xff0c;本质可以拆成 5 步&#xff1a;&#x1f449; 部署系统 → 配置基础 → 上架商品 → 打通交易 → 引流运营只要这 5 步跑通&#xff0c;就可以实现“可正常卖货”的商城。一、准备阶段&#xff08;很多人会忽略&#xff09;在动手之前…...

免费开源!3分钟让Mac鼠标滚动告别卡顿的终极平滑方案

免费开源&#xff01;3分钟让Mac鼠标滚动告别卡顿的终极平滑方案 【免费下载链接】Mos 一个用于在 macOS 上平滑你的鼠标滚动效果或单独设置滚动方向的小工具, 让你的滚轮爽如触控板 | A lightweight tool used to smooth scrolling and set scroll direction independently fo…...