微信小程序蓝牙BLE开发实战——案例(二)

摘自:微信小程序蓝牙BLE开发实战——案例(二)_Smile_ping的博客-CSDN博客

另一个参考:微信小程序BLE控制8266

文章目录
微信小程序蓝牙BLE开发实战(二)
项目介绍
效果图
扫码使用`格子柜`流程
蓝牙通讯协议
加密理解
实例(`蓝牙操作`功能)
一. 新建`js`文件及使用时引入
1. 定义全局变量
2. 自定义方法
3. 初始化蓝牙`入口`
4. 应用到`蓝牙`API方法
5. 处理`设备返回数据`及`操作指令`(如何发指令?)
6. 处理回调一些方法
7. 蓝牙连接过程中错误码
8. 导出方法
二 、在需要页面中调用`蓝牙`
1. 引入文件
2. 全局中定义处理回调函数
全局方法中如何给`data`中属性赋值
3. 调用执行`蓝牙`方法
4. 执行开锁
BLE项目实战下载
关于下篇内容
项目介绍
由于公司近阶段开发的共享产品比较多,有共享充电宝、陪护床等,这里就不一一介绍哈。大部分产品通过蓝牙通讯的。

快捷方便: 通过扫设备二维码进入小程序使用设备。

这里拿最近开发一个产品售卖机,生活中比较常见的一个,例如: 储物柜、格子柜等。
特点: 一个售卖机中有n个小格子(根据产品分类)
效果图


扫码使用格子柜流程
售卖机上有设备的二维码(自己生成普通二维码),直接扫码

ps: 有个别标注链接的,是个人在项目开发中应用总结知识点。

微信扫普通二维码进入小程序,授权获取用户信息 用户授权成功后,检测用户是否打开蓝牙
未打开时弹窗提示用户, 否则自动跳转到售卖机页面。
售卖机页面会展示售卖商品(比如8个,那么就展示8个商品)
选择需要购买的商品, 点击购买按钮
支付金额
支付完成后, 调用执行蓝牙方法开始搜索设备—>匹配设备—>连接设备...—>开锁成功(柜门打开) 【查看蓝牙具体流程】如连接设备失败,页面显示重连按钮
拿出商品,关好柜门(可返回购买页,继续购买)。
蓝牙通讯协议
主要通过与供应商提供的蓝牙板子、通讯协议和硬件对接,实现操控设备具备的功能。

不同的供应商设备蓝牙通讯协议有所不同。反之产品不同通讯流程也不同。

有些文档比较不规范,看起来会很茫然, 慢慢理解查资料

加密理解
基于数据安全性、完整性等等,蓝牙协议通过会在有加密的过程,抵御攻击者。

密码之AES五种加密模式(CBC、ECB、CTR、OCF、CFB)

下发某个指令时需要对数据进行加密,设备会返回数据,通过后再操作其他指令。
下发指令时加密, 得到设备返回数据后需要解密,如果验证通过,才可以继续操作后面流程。
不管使用哪种加密模式,会标注在协议文档或以其他方式说明

ps: 个人在项目中使用模式有 AES ECB 128、CFB 128, 还有最近使用一种CRC(循环冗余校验)来校验。
AES加解密案例

实例(蓝牙操作功能)
说明:

以下代码直接copy到.js中就可以使用。(这里有分段说明下,按顺序复制即可)
因在项目中对接设备比较多, 把蓝牙设备相关功能剥离到js文件中。
注意: 开发工具上不支持调试蓝牙功能的
【蓝牙API详情介绍请点击】
一. 新建js文件及使用时引入


1. 定义全局变量
根据个人需求适用

const app = getApp()
var utils = require('.././util.js');
var cryptoService = require('../bleFile/cryptoService.js'); //引入加密文件
var crc = require('../bleFile/crc.js'); //引入crc校验


var serviceUUID = [] //主 service 的 uuid 列表
var writeUUID = ""; //写读 UUID
var notifyUUID = ""; //notify UUID
var delayUUID = ""; //护眼仪控制时长UUID
var filterServiceUUID = ""; //过滤获取到的服务uuid(有些会返回多条数据)
var filterDeviceName = ""; //设备名称

var macAddress = ""; //保存得到mac地址
var flagFromTypes = ''; //来源类型(根据不同产品执行蓝牙协议)  例:1-->充电宝 2-->售卖机....
var _discoveryStarted = false;
var deviceId = ''; //用于区分设备的 id

var _deviceId = '';
var _serviceId = '';
var _characteristicId = '';
var status = false; //当前状态
var action_type = ''; //操作类型
var code = -1;
var isnotExist = true //防止多次执行

var asddCallBack = null; //接收数据处理
var asddErrorCallback = null; //接收错误码处理
var asddWriteErrors = null; //接收写入错误处理

var tempStr = ''; //拼接设备返回数据
var rssiVal = ''; //RSSI值
var currentSerialVal = ''; //当前点击格子柜序号


//当前操作类型
var OptionEnum = {
    None: -1,
    Connection: 0, //连接
    Reconnection: 1, //重连
    CloseLock: 2, //关闭
    VendingOpenLock: 8, //打开售卖机
    ReadStatus: 9, //读售卖机状态
    ReadBattery: 10, //读售卖机电量
};
//这个是变量, 存储数据的变量
var action_type = OptionEnum.None;
2. 自定义方法
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('');
}

/**
 * 去掉 冒号
 */
function clearSymbol(str) {
    str = str.replace(/:/g, ""); //取消字符串中出现的所有冒号
    return str;
}

/**
 *  匹配规则: 取名称后面的mac
 */
function getNameMac(macAddress, len, name) {
    let clearColonMac = clearSymbol(macAddress);
    let lastFourMac = clearColonMac.substring(clearColonMac.length - len);
    let strName = name.toUpperCase();
    strName = strName + lastFourMac.toUpperCase(); //转大写
    console.log('拼接后的' + strName);
    return strName
}


/**
 * 区分不同类型的服务相关uuid
 * 1-->充电宝 2-->售卖机
 */
function flagServiceIDFun(serviceType) {
    console.log('方法中拿到type======>', serviceType);
    if (serviceType == 1) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //写读 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";
    } else if (serviceType == 2) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //写读 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";
        
        //这里介绍用name匹配方法
        filterDeviceName = getNameMac(macAddress, 6, 'abc_'); //设备名称
    } 
}


3. 初始化蓝牙入口
注意: 在使用.js文件中, 只需要调用initBle()方法即可实现蓝牙实现整个过程。【方法里面每个步骤都有调用对应方法】

说明: 所有asddErrorCallback(res.errCode, "");为处理错误码回调, 在使用的页面中接收并处理回调函数。

/**
* 初始化蓝牙模块
* 参数1: mac地址
* 参数2: 当前操作类型
* 参数3: 当前点击格子的序号(第几个格子)
*/
function initBle(fromMac, flagTypes, currentSerial) {
    tempStr = ''; //清空

    //断开连接【每次初始化先断开连接】
    closeBLEConnection();

    console.log("你获取到mac地址了么....", fromMac + '获取到类型为====》' + flagTypes);
    // macAddress = clearSymbol(fromMac);
    macAddress = fromMac; //保存mac
    flagFromTypes = flagTypes //类型来源

    //获取RSSI值
    let getRssi = wx.getStorageSync('rssi');
    rssiVal = getRssi;

    //调用主服务id相关
    flagServiceIDFun(flagTypes);

    // 获取当前点击售卖机序号值
    currentSerialVal = currentSerial


    _discoveryStarted = false;

    //初始化蓝牙模块
    wx.openBluetoothAdapter({
        success: (res) => {
            console.log('openBluetoothAdapter 初始化蓝牙模块是否成功:', res)
            // 监听寻找新设备事件
            onBluetoothDeviceFound();

            //开始搜寻附近的蓝牙外围设备
            startBluetoothDevicesDiscovery();
        },
        fail: (res) => {
            console.log('初始化蓝牙失败', res);
            asddErrorCallback(res.errCode, "");
            
            //监听蓝牙适配器状态变化事件【根据需求是否执行】
            // wx.onBluetoothAdapterStateChange(function (res) {
            //     console.log('蓝牙适配器状态更改结果:  ', res)
            //     if (res.available) {
            //         console.log('蓝牙可用,搜索设备:--》 ')
            //         onBluetoothDeviceFound();
            //         startBluetoothDevicesDiscovery();
            //     }
            // })
        }
    })
}


4. 应用到蓝牙API方法
/**
 * 监听寻找新设备事件
 * 注意咯: 这里有展示三种不同方式来连接设备,请看备注【mac, name, 根据系统的】 各取所需吧。
 */
function onBluetoothDeviceFound() {
    wx.onBluetoothDeviceFound((res) => {
        console.log('广播数据结果:', res);

        res.devices.forEach(device => {
            if (!device.name && !device.localName) {
                return
            }

            // 转换后, 根据协议文档取需要数据 (advertisData不一定有数据)
            if (device.advertisData != null) { //判断对象是否为null,advertisData不一定有
                var hexStr = ab2hex(device.advertisData);
                console.log("广播数据中转换后:advertisData---->" + hexStr);
            }
            

            // 充电宝 android用mac, ios用name匹配
            if (flagFromTypes == 1) {
                if (app.getPlatform() == 'android') {
                    if ((macAddress != "") && (macAddress == device.deviceId) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;

                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                } else if (app.getPlatform() == 'ios') {
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;
                        
                        //停止搜寻附近的蓝牙外围设备
                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                }
            } else if (flagFromTypes == 2) {
                 //判断RSSI值在某个范围内时搜索设备,根据个人需求判断
                if (parseFloat(device.RSSI) > parseFloat(rssiVal)) {                
                    // 格子柜Android IOS通过名称匹配
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;
                        
                        //停止搜寻附近的蓝牙外围设备
                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                }
            } 
        })
    })
}

/**
 * 执行连接蓝牙设备
 */
function startBluetoothDevicesDiscovery() {
    if (_discoveryStarted) {
        return;
    }
    _discoveryStarted = true
    
    wx.startBluetoothDevicesDiscovery({
        services: serviceUUID,
        allowDuplicatesKey: false,
        success: (res) => {
            console.log('启动搜索蓝牙设备, 结果  :', res)
            //onBluetoothDeviceFound()  //先调用此方法再使用startBluetoothDevicesDiscovery
        },
        fail(res) {
            asddErrorCallback(res.errCode, "");
            console.log('startBluetoothDevicesDiscovery fail', res);
        }
    })
}


//停止搜寻附近的蓝牙外围设备。
function stopBluetoothDevicesDiscovery() {
    wx.stopBluetoothDevicesDiscovery()
}


/**
 * 连接蓝牙设备
 */
function createBLEConnection() {
    var that = this;
    wx.createBLEConnection({
        deviceId: deviceId,
        success: (res) => {
            wx.showToast({
                title: '设备连接成功',
                duration: 2000
            })
            //获取蓝牙所有服务
            getBLEDeviceServices(deviceId)
        },
        fail: (res) => {
            console.log('createBLEConnection fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
    stopBluetoothDevicesDiscovery(); //停止搜索
}


/**
 * 断开蓝牙连接
 */
function closeBLEConnection() {
    //停止搜索
    stopBluetoothDevicesDiscovery();

    tempStr = ''; //清空

    if (deviceId) {
        wx.closeBLEConnection({
            deviceId: deviceId,
            success: function(res) {
                console.log("closeBLEConnection。success", res);

            },
            fail: function(res) {
                console.log("closeBLEConnection。fail", res);
            },
            complete: function() {
                status = false;
            }
        })

        wx.closeBluetoothAdapter({
            success: function(res) {
                console.log("closeBluetoothAdapter ==>res:", res);
            },
            fail: function(error) {
                console.log("closeBluetoothAdapter ==>error:", error);
            }
        })
    }

    _discoveryStarted = false;
    isnotExist = true;
    _deviceId = '';
    deviceId = '';
}


/**
 * 获取蓝牙所有服务
 */
function getBLEDeviceServices(deviceId) {
    wx.onBLEConnectionStateChange(function(res) {
        console.log("onBLEConnectionStateChange:", res);
        // 该方法回调中可以用于处理连接意外断开等异常情况
        console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
        if (res.connected == false) {
            console.log("连接意外断开等****", _deviceId);
            _deviceId = '';
            if (flagFromTypes == 1 && flagFromTypes == 2) {
                asddErrorCallback(1010, ""); //?
            }
        }
    });

    wx.getBLEDeviceServices({
        deviceId: deviceId,
        success: (res) => {
            // console.log("获取蓝牙设备所有服务(service)", res);
            for (let i = 0; i < res.services.length; i++) {
                let tmpUuid = res.services[i].uuid;
                if ((res.services[i].isPrimary) && (tmpUuid.indexOf(filterServiceUUID) != -1)) {
                    getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
                    return
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceServices fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
}


/**
 * 获取蓝牙特征值
 */
function getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
        deviceId: deviceId,
        serviceId: serviceId,
        success: (res) => {
            // console.log('蓝牙设备特征值信息:', res);
            for (let i = 0; i < res.characteristics.length; i++) {
                let item = res.characteristics[i]
                var itemUUID = item.uuid.toUpperCase(); //转大写

                if (item.properties.read && itemUUID == writeUUID) {
                    wx.readBLECharacteristicValue({
                        deviceId: deviceId,
                        serviceId: serviceId,
                        characteristicId: item.uuid,
                    })
                }
                if (item.properties.write && itemUUID == writeUUID) {
                    _deviceId = deviceId
                    _serviceId = serviceId
                    _characteristicId = item.uuid

                    //发送指令【说明:如需连接设备后发相关指令可以在这里调用】
                      if (flagFromTypes == 1) { //充电宝
                        powerBank.send(); //充电开机指令
                    } else if (flagFromTypes == 2) { //售卖机
                        vendingObj.checkEnKey(); //AES校验
                    }
                }

                if (notifyUUID == itemUUID) {
                    if (item.properties.notify || item.properties.indicate) {
                        console.log('调用notifyBLECharacteristicValueChange前', item.uuid);
                        wx.notifyBLECharacteristicValueChange({
                            deviceId: deviceId,
                            serviceId: serviceId,
                            characteristicId: item.uuid,
                            state: true,
                            success(res) {
                                console.log('notification通知数据', res);
                                status = true;
                                // wx.hideLoading();
                            },
                            fail(res) {
                                console.log('notifyBLECharacteristicValueChange fali', res);
                            }
                        })
                    }
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceCharacteristics fail', res)
            asddErrorCallback(res.errCode, "");
        }
    })


    // 操作之前先监听,保证第一时间获取数据
    wx.onBLECharacteristicValueChange(function(res) {
        console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
        console.log("操作类型:" + action_type);

        var resData = ab2hex(res.value);
        console.log("设备返回数据--->", resData); //5d0000000001be304d

        // 判断不同类型处理数据
        if (flagFromTypes == 2) {
            console.log('开始调用 自动售卖机====> 处理返回的数据');
            vendingObj.handleResData(resData); //处理返回数据
        }
    })
}

/**
 * 写入数据
 */
function writeData(hex, action = '') {
    if (!status) {
        return;
    }

    if (!_deviceId) {
        asddWriteErrors('w');
        return;
    }

    setTimeout(() => {
        //向设备特征值中写入二进制数据
        //这里使用`TypedArray视图`中`Uint8Array(无符号 8 位整数)`操作
        var enDataBuf = new Uint8Array(hex);
        var buffer1 = enDataBuf.buffer

        wx.writeBLECharacteristicValue({
            deviceId: _deviceId,
            serviceId: _serviceId,
            characteristicId: _characteristicId,
            value: buffer1,
            success: (res) => {
                wx.hideLoading();
                console.log("写数据返回结果", res.errMsg);
            },
            fail(res) {
                console.log("写数据失败..", res);
                asddErrorCallback(res.errCode, "");
            }
        })
    }, 1000)
}


5. 处理设备返回数据及操作指令(如何发指令?)
以售卖机为例, 注意: 交互流程及指令格式根据文档说明

/**
 * 售卖机
 */
var vendingObj = {
    /**
     * 校验AES密钥
     * 字符、key文档有说明
     */
    checkEnKey: function() {
        status = true;
        var strKey = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var key = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var cryptoKey = new Uint8Array(key);
        enKEY = cryptoKey;
        //得出加密后的指令, 十六进制的数据
        var enHEX = cryptoService.updateEncrypt(strKey, enKEY);
        writeData(enHEX);
    },
    
    /**
     * 查询设备信息
     */
    queryDeviceInfo: function() {
        action_type = OptionEnum.ReadBattery; //改变操作类型
        let hex = [0x69, 0xf2, 0x00, 0x89];
        writeData(hex); //写入数据
    },
    
     /**
     * 开锁指令
     */
    openVendingLock: function(callBack) {
        status = true;
        action_type = OptionEnum.VendingOpenLock;
        asddCallBack = callBack;
        //获取当前开锁的编号及转换
        let getCurrentVal = Number(currentSerialVal);
        getCurrentVal = getCurrentVal.toString(16);
        // let tempVal = '0x0' + getCurrentVal;
        let tempVal = parseInt(getCurrentVal, 16);
        console.log('====开锁编号===》', tempVal);
        let hex = [0xfe, 0x4e, 0x30, 0x46, 0x4a, 0x00, tempVal, 0x00, 0x00, 0x3e];
        writeData(hex);
    },

    /**
     * 处理格子机查询信息电量回调
     * 目的:获取到相关数据,发送给后端(查看设备电量)
     */
    readBatteryCallBack: function(battery) {
        console.log("=======>>>电量:", battery);
        action_type = OptionEnum.None;

        //这里获取到电量, 返回给index.js页面
        if (asddCallBack != null) {
            asddCallBack(battery, OptionEnum.ReadBattery);
        } else {
            console.log("是否为空=======标签 2");
        }
    },
    
 
    /**
     * 处理开锁成功回调
     */
    openLockCallback: function(resData) {
        var isOpenLock = false;
        // 根据当前点击的柜子序号,截取对应的数据状态
        var star = Number(currentSerialVal) * 2
        var subSerial = resData.substring(star, star + 2);
        if (subSerial.toUpperCase() == 'F0') {
            isOpenLock = true;
        }
        console.log("=======>>>开锁:", isOpenLock ? "成功" : "失败");
        action_type = OptionEnum.None;

        if (asddCallBack != null) {
            asddCallBack(isOpenLock, OptionEnum.VendingOpenLock);
        } else {
            console.log("是否为空=======标签 3");
        }
    },

    
    /**
     * 处理返回数据
     * 例如: 00f05d09000001be304d
     */
    handleResData: function (resData) {
        let checkStatus = resData.substring(2, 4);

        if (checkStatus.toUpperCase() == 'F0' && action_type == OptionEnum.Connection) { //校验状态
            vendingObj.queryDeviceInfo(); //查询设备信息

        } else if (action_type == OptionEnum.ReadBattery) { //操作的是获取设备电量

            let batteryVal = resData.substring(6, 8);
            batteryVal = parseInt(batteryVal, 16);
            vendingObj.readBatteryCallBack(batteryVal);

        } else if (action_type == OptionEnum.VendingOpenLock) { //操作的是 开锁

            vendingObj.openLockCallback(resData);
        }
    }
}
6. 处理回调一些方法
//设置连接
function setConnectionActionType(callBack) {
    action_type = OptionEnum.Connection;
    asddCallBack = callBack;
}

//设置重连
function setReconnectionActionType() {
    action_type = OptionEnum.Reconnection;
}

// 设置错误
function setAsddErrorCallback(callBack) {
    asddErrorCallback = callBack;
}

//设置关闭
function setCloseActionType(callBack) {
    action_type = OptionEnum.CloseLock;
    asddCallBack = callBack;
}

//设置写入错误
function setWriteError(callBack) {
    asddWriteErrors = callBack;
}

//清除
function clearCallBack() {
    asddCallBack = null;
}

/**
 * 清空loadding
 */
function hideLoading() {
    wx.hideLoading();
}


/**
 * 检查是否打开蓝牙
 * 未连接设备前检测
 */
function checkIsOpenBluetooth(isEXec) {
    wx.openBluetoothAdapter({
        success: (res) => {
            // console.log('openBluetoothAdapter 初始化蓝牙模块是否成功:', res);
            isEXec(true);
        },
        fail: (res) => {
            // console.log('初始化蓝牙失败', res);
            wx.showModal({
                title: '提示',
                content: '请检查手机蓝牙是否打开',
                showCancel: false
            })

            isEXec(false);
        }
    })
}



7. 蓝牙连接过程中错误码
/**
 * 蓝牙连接过程中错误码
 * 10000 / 10006
 */
function bluetoothStatus(errorType) {
    switch (errorType) {
        case 10001:
            wx.showModal({
                title: '提示',
                content: '请检查手机蓝牙是否打开',
                showCancel: false
            })
            break;
        case 10002:
            wx.showToast({
                title: '没有找到指定设备',
                icon: 'none'
            })
            break;
        case 10003:
            wx.showToast({
                title: '连接失败',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10004:
            wx.showToast({
                title: '没有找到指定服务',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10005:
            wx.showToast({
                title: '没有找到指定特征值',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10007:
        case 10008:
        case 10013:
            wx.showToast({
                title: '设备启动失败,请重试',
                icon: 'none'
            })
            break;
        case 10009:
            wx.showModal({
                title: '提示',
                content: '当前系统版本过低,请更新版本体验',
                showCancel: false
            })
            break;
        case 10012:
            wx.showToast({
                title: '连接超时',
                icon: 'none'
            })
            break;
    }
}
8. 导出方法
外部需使用的方法,注意导出。否则无法使用

module.exports = {
    initBle: initBle,
    clearCallBack: clearCallBack,
    closeBLEConnection: closeBLEConnection,
    setConnectionActionType: setConnectionActionType,
    setReconnectionActionType: setReconnectionActionType,
    setAsddErrorCallback: setAsddErrorCallback,
    setCloseActionType: setCloseActionType,
    setWriteError: setWriteError,
    checkIsOpenBluetooth: checkIsOpenBluetooth,
    bluetoothStatus: bluetoothStatus,
    openVendingLock: vendingObj.openVendingLock,
}

二 、在需要页面中调用蓝牙
1. 引入文件
const app = getApp()
let commonBLE = require('../../../../../utils/fromCategory/commonBLE.js'); //公共BLE
let commonBLEDatas = null; //保存当前页面对象

2. 全局中定义处理回调函数
全局方法中如何给data中属性赋值
定义一个全局变量,来保存当前页面对象
在onLoad()中给变量赋值, 即commonBLEDatas = this
使用: 通过变量名.data.属性,即commonBLEDatas.data.battery = obj
/**
 * 处理返回部分数据回调函数
 * obj: 传过来的数据
 * types: 当前操作类型 【可在`commBLE.js`查看定义的】
 */
let callBack = function(obj, types) {
    console.log("index.js回调函数" + obj, types);
    // commonBLE.clearCallBack();
    if (commonBLEDatas.data.currentMeasureType == 4) { //售卖机
        if (types == 10) {
            //给电量赋值
            commonBLEDatas.data.battery = obj;
            
            //调用开锁指令
            commonBLEDatas.successOpenLock();
        } 
    }
}

/**
 * 处理错误码回调
 */
let errorCallBack = function(errorType, errorMessage) {
    // feedbackApi.hideTimerToast(); //清空loadding
    commonBLEDatas.deviceConnectFail(); //展示 设备连接失败
    if (errorType == 10000 || errorType == 10006) {
        //连接蓝牙
        commonBLE.setReconnectionActionType();
        commonBLE.setAsddErrorCallback(errorCallBack);
        commonBLE.setWriteError(writeError);
        if (commonBLEDatas.data.currentMeasureType == 4) {
            commonBLE.initBle(commonBLEDatas.data.macAdress, OptionEnumType.Vending, commonBLEDatas.data.currentSerial);
        } 
    } else {
        commonBLE.bluetoothStatus(errorType);
    }
}


/**
 * 写入失败回调
 */
let writeError = function(writeE) {
    console.log('写入数据状态', writeE);
    //写入错误页面展示状态
    commonBLEDatas.setData({
        connectStatus: 1,
        isConnect: 2,
        clickFlags: false
    })

    if (writeE == 'w') {
        feedbackApi.hideTimerToast(); //清空loadding
        clearInterval(commonBLEDatas.downSecondId); //清空倒计时

        wx.showToast({
            title: '连接失败,请再次尝试(0)',
            icon: 'none'
        })
        commonBLE.closeBLEConnection();
    }
}

3. 调用执行蓝牙方法
点击购买商品按钮, 执行此方法。
传参: 当前设备的mac地址(后台获取的)、操作的产品类型及操作序号(操作几号柜子)
说明: 柜子序号1,2,3,4…, 和页面展示商品对应的。

Page({

     /**
     * 页面的初始数据
     */
    data: {
        currentMeasureType: 2, //测试 当前类型售卖机
        macAdress: '3b3533115510', //mac地址(这里后台保存时没有:号的,可自行处理)
        currentSerial: '', //当前操作格子序号
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function(options) {
        commonBLEDatas = this;
    },
    
   /**
    * 连接BLE
    */
    connectVendingBLE: function() {
        let that = this;
        commonBLE.setConnectionActionType(callBack); //连接后操作回调
        commonBLE.setAsddErrorCallback(errorCallBack); //执行错误时错误码回调
        commonBLE.setWriteError(writeError); //写入数据错误回调
        if (that.data.currentMeasureType == 2) {
            commonBLE.initBle(that.data.macAdress, OptionEnumType.Vending, that.data.currentSerial);
        } 
    },
    
    /**
     * 设备连接失败
     */
    deviceConnectFail: function () {
        // feedbackApi.hideTimerToast(); //清空loadding
        clearInterval(this.downSecondId); //清空倒计时
        this.setData({
            descTxt2: '设备连接失败',
            connectStatus: 1,
            isConnect: 2,
            clickFlags: false
        })
    },
})


4. 执行开锁
如获取电量成功后, 执行开锁指令,成功后页面展示对应【具体流程根据需求来】

/**
* 售卖机开锁成功后提交数据  并展示相关的ui
* 写在 Page({})中的, 这里为了说明写在外面
*/
successOpenLock: function() {
    let that = this;
    // 调用开锁及处理回调数据
    commonBLE.openVendingLock(function(isOpenLock, obj) {
        console.log('处理开锁指令回调====》' + isOpenLock);
        commonBLE.clearCallBack();
        
        var tempStr = "失败";
        if (isOpenLock) {
            tempStr = "成功";
            // 提交数据并展示成功开锁后Ui
            that.showSuccessBack();
        }else {
            wx.showToast({
                title: "开锁" + tempStr,
                duration: 3000,
                image: '/page/common/libs/assets/images/error.png',
            })

            that.deviceConnectFail(); //展示 设备连接失败
            //断开蓝牙连接
            commonBLE.closeBLEConnection();
        }
    });
},
    
1
BLE项目实战下载
蓝牙BLE项目实战
————————————————
版权声明:本文为CSDN博主「Smile_ping」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Smile_ping/article/details/103148061

你可能感兴趣的:(微信小程序,小程序,嵌入式硬件)