客户的需求如下:通过微信小程序控制蓝牙ble设备(电子面膜),通过不同指令控制面膜的亮度和时间。
01.首先看下客户的ble设备服务文档:(本部分需要有点蓝牙基础,在调试过程中可以用安卓软件nRF Connect软件来执行测试命令)
UUID | 名称 | 特征属性 | 说明 |
FFF0 | 灯控服务 | ||
FFF1 | 灯控命令 | Write | APP 发命令给设备 |
FFF2 | 灯状态 | Notify | 设备发状态给APP |
FFF3 | 验证码通道 | Write / Read | 用户验证码 |
FFF4 | 电池状态 | Notify | 设备发电池状态给APP |
FFF8 | 修改密码 | Write/Read | |
FFF9 | 修改设备名称 | Write/Read |
命令格式:
字段 | 头 | 命令类型 | 命令数据 | 当前连接加密码 |
内容 | 0xFA | |||
字节数 | 1 | 1 | 3 | 2 |
命令类型:
0x01 – 常规模式,命令数据第一个字节为模式(1-3表示模式1-3),第二个字节为开关状态(0为暂停,1为启动)。
0x02 – 个性模式,命令数据第一个数据为强度百分比(1-100),第二个字节是时间低位,第三个字节是时间高位(单位秒)。
4个字节,数据同灯控命令的(命令类型+命令数据)。
通道用户连接时加密验证,该通道具有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];
}
6个字节,字节1为电池电压高8位,字节2为电池电压低8位;字节3为电池电流高8位,字节4为电池电流低8位;字节5为电池电量(1-5),1表示低电量,5表示满电量;字节6为工作计时,为0时表示负载开路。
验证成功后,可以通过该通道进行修改密码:
密码应为字符格式。
数据格式:共12字节:
旧密码 | 新密码 | 新密码(重复) |
4Bytes | 4Bytes | 4Bytes |
修改密码应该在 500~1000ms 以后读取该通道,读到0x01 说明密码修改成功,否则失败。
验证成功后,可以通过该通道进行修改设备广播名称:
数据格式:1~20字节:
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地址,我处理过.不能直接用搜索列表的deviceId var 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(); //Mac var Tempmac = macstring.split(':'); for (var i = 0; i < Tempmac.length; i++) { Tempmac[i] = '0x' + Tempmac[i]; } var mac = new Uint8Array(Tempmac); //Mac-End //Rand var 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-End 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]; 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.buffer wx.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) } })
附上小程序蓝牙项目地址,可正常运行.star谢谢
gitup地址:我是飞机票
c#中string和StringBuilder直接看看执行速度。(2).String类型累计赋值Test  ...
1.全局用户信息设置 git config --global user.name gaojiufeng git config --global user.email 392223903...
Application 对象用于存储和访问来自任意页面的变量,类似 Session 对象。不同之处在于所有的用户分享一个 Application 对象,而 session 对象和用户的关系是一一对应的。很多的书籍中介绍的Application对象都喜欢以统计在线人数来介绍Application 对象...
git pull https://git.oschina.net/392223903/learn.git master 换为您的git地址...
日志查看:git log版本切换:方式1:git reset --hard HEAD^ 倒退一个版本git reset --hard HEAD^^ 倒退两个版本方式2:(版本号的形式,建议版本号码补充完...
public static string GetMD5(string str) { //创建MD5对象 MD5 md5 = MD5.C...