小程序使用蓝牙功能获取充电柜电池信息

由于公司业务做的是物联网智能充电柜,刚好最近的需求涉及到调用小程序蓝牙功能连接获取电池信息。鉴于网上大部分资料都是基于蓝牙多个特征值来实现,本文案例基于一个特征值通过写入不同的指令来实现不同数据的读取,于是就出现了这篇文章。

一、业务需求
点击电池按钮进入电池信息页面,点击底部的按钮获取附近的蓝牙设备列表,选择匹配公司业务的蓝牙进行连接,连接成功返回对应的蓝牙信息数据;包括电池名称、电池电压等,这些数据会定时刷新,类似websocket的即时通讯功能。

二、硬件交互
这边硬件给我们反馈的信息比较特殊,整个蓝牙模块只有一个特征值,通过写入不同的指令区分数据类型;比如特征值AAAA,获取电池配置的写入指令为85,获取电池信息的指令为90。而不是一个特征值对应一个数据类型,如特征值BBBB,通过读取指令返回电池配置,特征值CCCC返回电池信息。
蓝牙返回的信息数据是一串二进制的字节,超过20字节会被拆包发送。返回的全部参数都拼接在一起,需要前端进行切割。如0080000060je0000015467978,最前面两个字节00代表电池号。
一般为了数据安全起见,不会开启读取的权限。前端一般不会通过read()方法来读取数据,而是通过write()写入指令的方法来实现。当然了,这少不了加密,这边用的是crc-8计算规则,由于网上找不到对应方法,因此通过接口来实现。

三、蓝牙硬件协议文档


emmm,这份协议文档对我前端来说,真的看不懂。后来经过和我们技术大佬沟通了N遍才明白了。
注:一个字节2个字符串

四、小程序蓝牙交互流程

流程图

  • 初始化蓝牙
  • 判断本机蓝牙适配器是否可用
  • 开启蓝牙搜索
  • 开始搜索周边蓝牙设备
  • 连接蓝牙
  • 获取蓝牙对应的服务列表
  • 获取对应服务列表下的所有特征值(该蓝牙是否可读写可监听消息推送等信息)
  • 开启消息监听
  • 对蓝牙进行读写操作(写入数据需要把json格式转成2进制格式,再分包发送)
    (因系统与蓝牙单次传输只能发送20个字节, 因此大于20个字节时需要手动分包发送。)

五、涉及知识点

  • 十六进制转十进制
  • 十六进制转二进制
  • arraybuffer转十六进制
  • 字符串转arraybuffer
  • crc-8/itu校验
  • 拆包
  • 拼包
  • 大端转小端(十六进制高低位置换)
  • 开尔文(k)温度转摄氏温度(°c)

六、重点代码

// 监听寻找到新设备的事件
onBluetoothDeviceFound() {
  uni.onBluetoothDeviceFound((res) => {
    console.log("监听寻找到新设备的事件", res, res.devices);
    //不重复 就添加到bluetoothList中
    if (
      !this.bluetoothList.some((item) => {
      return item.deviceId === res.devices[0].deviceId;
    })
    ) {
    // this.bluetoothList.push(res.devices[0])
    // 蓝牙前缀是:LSBMS_ 过滤掉即可
    res.devices.forEach((item) => {
      // 过滤为空的设备 mac没有localName这个字断
      if ((item.name || item.localName).indexOf("LSBMS_") > -1) {
      // this.bluetoothList.push(item);
      console.log('item-LSBMS_', item, this.batteryName)
      // 匹配已经连接的电池
      if (item.name == this.batteryName) {
      // 在个人中心点进来会携带一个当前租用的电池 列表中默认选中
      this.bluetoothList.push({
        ...item,
        isCheck: true
      });
    } else {
      this.bluetoothList.push({
        ...item,
        isCheck: false
      });
          }
        }
      });
    }
  });
},
                        // 开启消息监听 前提必须拿到设备ID、服务ID、特征值
            notify() {
                let params = {
                    deviceId: this.deviceId,
                    serviceId: this.bluetoothParams.serviceId,
                    characteristicId: this.bluetoothParams.characteristicId
                };
                console.log("params: ", params);
                uni.notifyBLECharacteristicValueChange({
                    ...params,
                    state: true, // 关键参数
                    success: (res) => {
                        console.log("res: ", res);
                    },
                    fail: (err) => {
                        console.error(err);
                        uni.hideLoading();
                    },
                });
            },
             // 接受消息 只有推送了才会响应
            // 拆包接收这边硬件给过来的参数是以aaaaaa6个a作为结尾 一次数据
            listenValueChange() {
                console.log("----");
                uni.onBLECharacteristicValueChange((res) => {
                    console.log("res: 接收消息", res);
                    // ArrayBuffer类型
                    let resHex = this.ab2hex(res.value);
                    console.log('resHex-----------', resHex);
                    // 以aaaaaa6个a作为结尾 一次数据 再进行监听
                    if (resHex.indexOf('aaaaaa') != -1) {
                        this.str = this.str + resHex
                        this.resultStr = this.str
                        this.str = ""
                    } else {
                        this.str = this.str + resHex
                    }
                    // 这里才算读取蓝牙数据结束 如果没有数据会一直转圈加载中
                    uni.hideLoading();
                });
            },
              async write() {
                // let msg = '028555D8AAAAAA'
                // 获取电池包状态 msgid(00-255)、cmd-type为80、playload为55、crc通过前面三个参数加密而成、endTag终止符AAAAAA
                // let msgId = "00";
                // let cmd = 80
                // let playload = 55

                this.str = ""
                this.resultStr = ""
                if (this.msgId == 255) {
                    this.msgId = "00"
                }
                
                // crc8校验网上找不到 因此调后端接口
                let resultCrc = await this.$http.get('account/account/get-crc', {
                    packet: this.msgId + this.cmd + this.playload,
                }).then((response) => {
                    console.log('response--------urc8', response)
                    return response.crc8_itu
                });
                // let endTage = 'AAAAAA'
                let hex = this.msgId + this.cmd + this.playload + resultCrc + this.endTage
                // 累加 不能大于255
                let id = Number(this.msgId) + 1
                this.msgId = id < 9 ? "0" + id : id
                console.log('this.msgId累加后', this.msgId)
                console.log('hex--------------------', hex)
                // let hex = '01805524AAAAAA'
                let arrayBuffer = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h) {
                    return parseInt(h, 16)
                }))
                arrayBuffer = arrayBuffer.buffer;
                uni.writeBLECharacteristicValue({
                    deviceId: this.deviceId,
                    serviceId: this.bluetoothParams.serviceId,
                    characteristicId: this.bluetoothParams.characteristicId,
                    value: arrayBuffer,
                    success(res) {
                        console.log('写入成功', res)
                    },
                    fail(err) {
                        console.error(err)
                    }
                })
            },

七、效果图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容