为您推荐:
精华内容
最热下载
问答
  • 116KB qq_24219911 2020-07-21 12:47:35
  • 19KB weixin_42696271 2021-09-11 04:01:43
  • 73KB weixin_38592848 2021-03-29 19:47:20
  • 闲来没事钻研小程序开发,写了一篇关于微信小程序ble设备控制的底层api,话不多说直接上源码: 目录结构: baseBleApi.js文件: varcurrentDevice = {};//ble设备 varnotifyService = {};/...

    转载自:

    https://blog.csdn.net/vhaiyue/article/details/78316225

    闲来没事钻研小程序开发,写了一篇关于微信小程序ble设备控制的底层api,话不多说直接上源码:

    目录结构:

    baseBleApi.js文件:

     

    var currentDevice = {};//ble设备

     

    var notifyService = {};//唤醒特征值

    var writeService = {};//写入服务

     

    var writeCharacteristic = {};//写入特征值

    var notifyCharacteristic = {};//唤醒特征值

     

    var onSendSuccessCallBack = undefined;//成功回调

    var onConnectCallback = undefined;// 链接回调

    var bleUtils = require('utils/strUtils.js');

    var crc = require('crc.js');

    var isConnected = false;//是否已链接


     

    module.exports = {

    writeCommend: writeCommend,

    closeBLEConnection: closeBLEConnection

    // disConnect, disConnect,

    // openBluetoothAdapter: openBluetoothAdapter

    }


     

    /**

    * @param sendCommend 写入命令

    * @param deviceName 锁具名称

    * @param onSuccessCallBack 成功回调

    * @param onFailCallBack 返回失败回调

    * @param onCompleteCallBack 成功失败都会回调

    *

    * @param services 主服务serviceUUID

    * @param writeServiceUUID 写入服务UUID

    * @param notifyServiceUUID 唤醒服务UUID

    *

    * @param notifyCharacteristicUUID 唤醒特征值UUID

    * @param writeCharacteristicUUID 写入特征值UUID

    */

     

    function writeCommend(options) {

    var params = {};

    var defalt = {

    adviceId: "",

    sendCommend: "",

    onSuccessCallBack: function success(res) { },

    onFailCallBack: function success(res) { },

    onCompleteCallBack: function success(res) { },

    services: [],

    writeServiceUUID: "",

    notifyServiceUUID: "",

    notifyCharacteristicUUID: "",

    writeCharacteristicUUID: ""

    };

     

    params = Object.assign(defalt, options)

    // setConnectionStateChange(params.onFailCallBack)

     

    if (!setConnectionStateChange()) {

    openBluetoothAdapter(params);

    } else {

    // typeof str == 'string'

    sendCmd(params.sendCommend, params.onSuccessCallBack, params.onFailCallBack);

    }

    }

     

    /**

    * 初始化蓝牙适配器

    */

     

    function openBluetoothAdapter(params) {

     

    wx.openBluetoothAdapter({

    success: function (res) {

    console.log("初始化蓝牙适配器成功")

    console.log(res)

    startBluetoothDevicesDiscovery(params)

     

    }, fail: function (res) {

    console.log("初始化蓝牙适配器失败")

    params.onFailCallBack(res.errMsg)

    console.log(res);

    return

    },

    complete: function (res) {

    console.log(res);

    }

    })

    }

     

    /**

    * 开始搜寻附近的蓝牙外围设备。注意,该操作比较耗费系统资源,请在搜索并连接到设备后调用 stop 方法停止搜索。

    * @ params services:['4asdga'],根据主ServiceUUID进行搜索特定蓝牙,提高搜索效率

    * 本ble设备主ServiceUUid: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"

    */

     

    var delayTimer;//停止循环获取tag

    var isFound = false

    function startBluetoothDevicesDiscovery(params, connectCallback) {

     

    if (typeof connectCallback == 'undefined') {

    connectCallback = function (errMsg) { }

    }

     

    onConnectCallback = connectCallback;

     

    setTimeout(function () {

    if (isFound) {

    return;

    }

    else {

    console.log("搜索设备超时");

    params.onFailCallBack("搜索设备超时")

    stopBluetoothDevicesDiscovery();

    clearInterval(delayTimer)

    return

    }

    }, 10000);

     

    wx.startBluetoothDevicesDiscovery({

     

    services: params.services,

    success: function (res) {

    console.log(res)

    console.log("开启搜索成功")

    getBluetoothDevices(params)

     

    }, fail: function (res) {

    console.log("开启搜索失败")

    console.log(res)

    params.onFailCallBack(res)

    return

    },

    complete: function (res) {

    // complete

    console.log(res);

    }

    })

     

    //每隔一秒获取一次

    delayTimer = setInterval(function () {

    getBluetoothDevices(params)

    }, 1000)

     

    }


     

    /**

    * 获取所有已发现的蓝牙设备,包括已经和本机处于连接状态的设备

    */

    function getBluetoothDevices(params) {

     

    wx.getBluetoothDevices({

    success: function (res) {

    console.log("getBluetoothDevices");

    console.log(res.devices);

    for (var i = 0; i < res.devices.length; i++) {

    //忽略传入的deviceName大小写

    // isContains bleUtils

    var lockNameFinal = bleUtils.removeBytes(params.adviceId, ":")

     

    if (bleUtils.isContains(res.devices[i].name, lockNameFinal)) {

    console.log("搜索到要链接的设备....")

    stopBluetoothDevicesDiscovery();

    isFound = true

    clearInterval(delayTimer)

    currentDevice = res.devices[i]

    createBLEConnection(params)

    }

    }

    },

    fail: function (res) {

    clearInterval(delayTimer)

    console.log("没有搜索到要链接的设备....")

    console.log(res)

    params.onFailCallBack(res)

    stopBluetoothDevicesDiscovery();

    return

    }

    })

    }

     

    /**

    * 停止搜寻附近的蓝牙外围设备。请在确保找到需要连接的设备后调用该方法停止搜索。

    */

    function stopBluetoothDevicesDiscovery() {

    wx.stopBluetoothDevicesDiscovery({

    success: function (res) {

    console.log(res)

    }

    })

    }

     

    /**

    * 连接低功耗蓝牙设备

    */

    function createBLEConnection(params) {

     

    // setConnectionStateChange(params.onFailCallBack);

     

    setTimeout(function () {

    if (isConnected) return;

    console.log("连接设备超时");

    params.onFailCallBack("连接设备超时")

    return

    }, 5000)

     

    wx.createBLEConnection({

    // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取

    deviceId: currentDevice.deviceId + "",

    success: function (res) {

    console.log(res)

    console.log(`连接成功 : ${currentDevice.deviceId}`)

    isConnected = true

    getBLEDeviceServices(params);

     

    }, fail: function (res) {

    console.log(res)

    params.onFailCallBack(res)

    console.log(`连接失败 : ${currentDevice.deviceId}`)

    }

    })

    }

    /**

    * closeBLEConnection

    * 断开与低功耗蓝牙设备的连接

    */

     

    function closeBLEConnection(deviceId) {

     

    wx.closeBLEConnection({

    deviceId: currentDevice.deviceId + "",

    success: function (res) {

    console.log(res)

    }

    })

    }



     

    /**

    *

    * 返回蓝牙是否正处于链接状态

    */

    function setConnectionStateChange(onFailCallback) {

    wx.onBLEConnectionStateChange(function (res) {

    // 该方法回调中可以用于处理连接意外断开等异常情况

    console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`);

    return res.connected;

    });

    }

     

    /**

    * 获取蓝牙设备所有 service(服务)

    * @params writeServiceUUID:ble设备所具有的写入服务UUID

    * @params notifyServiceUUID:ble设备具有的唤醒服务UUID

    */

     

    function getBLEDeviceServices(params) {

     

    wx.getBLEDeviceServices({

    // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取

    deviceId: currentDevice.deviceId + "",

    success: function (res) {

    console.log(`获取服务成功 :`)

    console.log('device services:', res.services)

     

    for (var i = 0; i < res.services.length; i++) {

    if (res.services[i].uuid == params.writeServiceUUID) {

    writeService = res.services[i]

    }

    if (res.services[i].uuid == params.notifyServiceUUID) {

    notifyService = res.services[i]

    }

    }

    //获取

    getNotifyBLEDeviceCharacteristics(params);

    }

    })

    }

     

    /**

    * 获取蓝牙设备唤醒characteristic(特征值)

    */

    function getNotifyBLEDeviceCharacteristics(params) {

     

    wx.getBLEDeviceCharacteristics({

    // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取

    deviceId: currentDevice.deviceId + "",

    // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取

    serviceId: notifyService.uuid + "",

     

    success: function (res) {

    console.log("唤醒特征值获取成功:")

    console.log('device getBLEDeviceCharacteristics:', res.characteristics)

     

    for (var i = 0; i < res.characteristics.length; i++) {

    if (res.characteristics[i].uuid == params.notifyCharacteristicUUID) {

    notifyCharacteristic = res.characteristics[i]

    }

    }

     

    // getWriteBLEDeviceCharacteristics();

    console.log("唤醒特征值 :", notifyCharacteristic)

    getWriteBLEDeviceCharacteristics(params)

    }

    })

    }

     

    function getWriteBLEDeviceCharacteristics(params) {

     

    wx.getBLEDeviceCharacteristics({

    // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取

    deviceId: currentDevice.deviceId + "",

    // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取

    serviceId: writeService.uuid + "",

     

    success: function (res) {

    console.log("写入特征值获取成功:")

    console.log('device getBLEDeviceCharacteristics:', res.characteristics)

    for (var i = 0; i < res.characteristics.length; i++) {

    if (res.characteristics[i].uuid == params.writeCharacteristicUUID) {

    writeCharacteristic = res.characteristics[i]

    }

    }

    console.log("xieru :", writeCharacteristic)

    initNotifyListener(params);

    }

    })

    }

     

    /**

    *

    * 连接成功后,初始化回调监听

    *

    * 启用低功耗蓝牙设备特征值变化时的 notify 功能。注意:\

    * 必须设备的特征值支持notify才可以成功调用,具体参照 characteristic 的 properties 属性

    */

    function initNotifyListener(params) {

     

    wx.notifyBLECharacteristicValueChanged({

     

    deviceId: currentDevice.deviceId + "",

    serviceId: notifyService.uuid + "",

    characteristicId: notifyCharacteristic.uuid + "",

    state: true,

     

    success: function (res) {

    console.log(`开启监听成功${res.errMsg}`);

     

    setTimeout(function () {

    onConnectCallback('ok');// 连接成功后,初始化回调监听回调

    sendCmd(params.sendCommend, params.onSuccessCallBack, params.onFailCallBack);

    }, 200);

    },

    fail: function (res) {

    console.log("开启监听失败" + res.errMsg);

    params.onFailCallBack("开启监听失败");

    }

    });

    onBLECharacteristicValueChange();

    }

     

    /**

    * 启用低功耗蓝牙设备特征值变化时的 notify 功能。注意:

    * 必须设备的特征值支持notify才可以成功调用,具体参照 characteristic 的 properties 属性

    */

    function onBLECharacteristicValueChange() {

    wx.onBLECharacteristicValueChange(function (res) {

    console.log(`characteristic ${res.characteristicId} has changed, now is ${bleUtils.arrayBuffer2HexString(res.value)}`);

    onSendSuccessCallBack(bleUtils.arrayBuffer2HexString(res.value));

    })

    }

     

    /**

    * 发送指令,不关心指令具体长度

    * @param commond 指令

    * @param onSuccess 指令执行成功回调

    */

    function sendCmd(commond, onSuccess, onFailCallback) {

     

    var sendCommonds = crc.getCRCCmd(commond);//对commond的CRC处理必须放在这里

    if (typeof onSuccess == 'undefined') {

    onSuccess = function (result) { }

    }

    onSendSuccessCallBack = onSuccess;

    sendCmds(sendCommonds, 0, onFailCallback);

    }

     

    /**

    *

    * 逐条发送指令

    */

    function sendCmds(commond, index, onFailCallback) {

    var itemCmd;

    var isLast = false;// 判断是否是最后一条

    if (commond.length > index + 40) {

    itemCmd = commond.substr(index, 40);

    } else {

    isLast = true;

    itemCmd = commond.substr(index);

    }

    writeCommendToBle(itemCmd, function (errMsg) {

    if (errMsg == 'ok' && !isLast) { // 发送成功并且不是最后一条时,执行下一条

    sendCmds(commond, index + 40);

    }

     

    }, onFailCallback)

    }

     

    // 向蓝牙中写入数据(ble蓝牙)(增加指纹)

    function writeCommendToBle(commonds, onSendCallback, onFailCallback) {

    var commond = commonds;

    console.log("commond :" + commond)

    let buffer = bleUtils.hexString2ArrayBuffer(commond);

    console.log(`执行指令:${bleUtils.arrayBuffer2HexString(buffer)}`);

     

    wx.writeBLECharacteristicValue({

    deviceId: currentDevice.deviceId + "",

    serviceId: writeService.uuid + '',

    characteristicId: writeCharacteristic.uuid + '',

    // 这里的value是ArrayBuffer类型

    value: buffer,

    success: function (res) {

    console.log('发送指令成功')

    console.log('writeBLECharacteristicValue success', res.errMsg)

    onSendCallback('ok');

    },

    fail: function (res) {

    console.log(`执行指令失败${res.errMsg}`);

    onFailCallback("执行指令失败");

     

    }

    })

    }

     

     

    crc.js文件:

    function CRC16(data) {

    var len = data.length;

    if (len > 0) {

    var crc = 0xFFFF;

     

    for (var i =0; i < len; i++) {

    crc = (crc ^ (data[i]));

    for (var j =0; j < 8; j++) {

    crc = (crc & 1) != 0 ? ((crc >> 1) ^ 0xA001) : (crc >> 1);

    }

    }

    var hi = ((crc & 0xFF00) >> 8); //高位置

    var lo = (crc & 0x00FF); //低位置

     

    // return [hi, lo];

    return [lo, hi]; // 大端模式

    }

    return [0,0];

    };

     

    function isArray(arr) {

    return Object.prototype.toString.call(arr) ==='[object Array]';

    };

     

    function ToCRC16(str, isReverse) {

    return toString(CRC16(isArray(str) ? str : strToByte(str)), isReverse);

    };


     

    function strToByte(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var j = encodeURI(tmp[i]);

    if (j.length == 1) {

    arr.push(j.charCodeAt());

    } else {

    var b = j.split('%');

    for (var m =1; m < b.length; m++) {

    arr.push(parseInt('0x' + b[m]));

    }

    }

    }

    return arr;

    };

     

    function convertChinese(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var s = tmp[i].charCodeAt();

    if (s <= 0 || s >=127) {

    arr.push(s.toString(16));

    }

    else {

    arr.push(tmp[i]);

    }

    }

    return arr;

    };

     

    function filterChinese(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var s = tmp[i].charCodeAt();

    if (s > 0 && s <127) {

    arr.push(tmp[i]);

    }

    }

    return arr;

    };

     

    function strToHex(hex, isFilterChinese) {

    hex = isFilterChinese ? filterChinese(hex).join('') : convertChinese(hex).join('');

     

    //清除所有空格

    hex = hex.replace(/\s/g, "");

    //若字符个数为奇数,补一个空格

    hex += hex.length % 2 != 0 ? " " : "";

     

    var c = hex.length / 2, arr = [];

    for (var i =0; i < c; i++) {

    arr.push(parseInt(hex.substr(i * 2, 2), 16));

    }

    return arr;

    };

     

    function padLeft(s, w, pc) {

    if (pc == undefined) {

    pc = '0';

    }

    for (var i =0, c = w - s.length; i < c; i++) {

    s = pc + s;

    }

    return s;

    };

     

    function toString(arr, isReverse) {

    if (typeof isReverse =='undefined') {

    isReverse = true;

    }

    var hi = arr[0], lo = arr[1];

    return padLeft((isReverse ? hi + lo * 0x100 : hi * 0x100 + lo).toString(16).toUpperCase(),4,'0');

    };

     

    function CRC16(data) {

    var len = data.length;

    if (len > 0) {

    var crc = 0xFFFF;

     

    for (var i =0; i < len; i++) {

    crc = (crc ^ (data[i]));

    for (var j =0; j < 8; j++) {

    crc = (crc & 1) != 0 ? ((crc >> 1) ^ 0xA001) : (crc >> 1);

    }

    }

    var hi = ((crc & 0xFF00) >> 8); //高位置

    var lo = (crc & 0x00FF); //低位置

     

    // return [hi, lo];

    return [lo, hi]; // 大端模式

    }

    return [0,0];

    };

     

    function ToCRC16(str, isReverse) {

    return toString(CRC16(isArray(str) ? str : strToByte(str)), isReverse);

    };

     

    function ToModbusCRC16(str, isReverse) {

    return toString(CRC16(isArray(str) ? str : strToHex(str)), isReverse);

    };


     

    /**

    * 给命令增加CRC 16进制

    *

    * @param hex

    * @return 16进制

    */

    function getCRCCmd(hex) {

    var hexTemp = hex;

    if (hex.toUpperCase().startsWith("0X")) {

    hexTemp = hex.substr(4);

    } else if (hex.toUpperCase().startsWith("AA")) {

    hexTemp = hex.substr(2);

    }

    return hex + getCRCStr(hexTemp);

    }

     

    /**

    * 获取CRC 16进制

    *

    * @param data

    * @return

    */

    function getCRCStr(data) {

    return ToModbusCRC16(data);

    }




     

    module.exports = {

    ToCRC16: ToCRC16,

    ToModbusCRC16: ToModbusCRC16,

    getCRCCmd: getCRCCmd

    }

     

     

     

    strUtils文件:

     

    /**

    * ArrayBuffer转16进制字符串

    */

    function arrayBuffer2HexString(buf) {

    var out = "";

    var u8a = new Uint8Array(buf);

    var single;

    for (var i =0; i < u8a.length; i++) {

    single = u8a[i].toString(16)

    while (single.length < 2) single = "0".concat(single);

    out += single;

    }

    return out;

    }

     

    /**

    * 1、字符串转换为十六进制

    * 主要使用 charCodeAt()方法,此方法返回一个字符的 Unicode 值,该字符位于指定索引位置。

    */

    function stringToHex(str) {

    var val = "";

    for (var i =0; i < str.length; i++) {

    val += str.charCodeAt(i).toString(16);

    }

    return val;

    }


     

    function filterChinese(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var s = tmp[i].charCodeAt();

    if (s > 0 && s <127) {

    arr.push(tmp[i]);

    }

    }

    return arr;

    };

    function strToHex(hex, isFilterChinese) {

    hex = isFilterChinese ? filterChinese(hex).join('') : convertChinese(hex).join('');

     

    //清除所有空格

    hex = hex.replace(/\s/g, "");

    //若字符个数为奇数,补一个空格

    hex += hex.length % 2 != 0 ? " " : "";

     

    var c = hex.length / 2, arr = [];

    for (var i =0; i < c; i++) {

    arr.push(parseInt(hex.substr(i * 2, 2), 16));

    }

    return arr;

    };

     

    /**

    * 16进制字符串转ArrayBuffer

    */

    function hexString2ArrayBuffer(hexStr) {

    var count = hexStr.length / 2;

    let buffer = new ArrayBuffer(count);

    let dataView = new DataView(buffer);

    for (var i =0; i < count; i++) {

    var curCharCode = parseInt(hexStr.substr(i *2, 2), 16);

    dataView.setUint8(i, curCharCode);

    }

    return buffer;

    }

     

    /**

    * 字符串转为ArrayBuffer对象,参数为字符串

    */

    function string2ArrayBuffer(str) {

    var buf = new ArrayBuffer(str.length *2); // 每个字符占用2个字节

    var bufView = new Uint8Array(buf);

    for (var i =0, strLen = str.length; i < strLen; i++) {

    bufView[i] = str.charCodeAt(i);

    }

    return buf;

    }

     

    function isArray(arr) {

    return Object.prototype.toString.call(arr) ==='[object Array]';

    };



     

    function strToByte(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var j = encodeURI(tmp[i]);

    if (j.length == 1) {

    arr.push(j.charCodeAt());

    } else {

    var b = j.split('%');

    for (var m =1; m < b.length; m++) {

    arr.push(parseInt('0x' + b[m]));

    }

    }

    }

    return arr;

    };

     

    function convertChinese(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var s = tmp[i].charCodeAt();

    if (s <= 0 || s >=127) {

    arr.push(s.toString(16));

    }

    else {

    arr.push(tmp[i]);

    }

    }

    return arr;

    };

     

    function filterChinese(str) {

    var tmp = str.split(''), arr = [];

    for (var i =0, c = tmp.length; i < c; i++) {

    var s = tmp[i].charCodeAt();

    if (s > 0 && s <127) {

    arr.push(tmp[i]);

    }

    }

    return arr;

    };

     

    function strToHex(hex, isFilterChinese) {

    hex = isFilterChinese ? filterChinese(hex).join('') : convertChinese(hex).join('');

     

    //清除所有空格

    hex = hex.replace(/\s/g, "");

    //若字符个数为奇数,补一个空格

    hex += hex.length % 2 != 0 ? " " : "";

     

    var c = hex.length / 2, arr = [];

    for (var i =0; i < c; i++) {

    arr.push(parseInt(hex.substr(i * 2, 2), 16));

    }

    return arr;

    };

     

    function padLeft(s, w, pc) {

    if (pc == undefined) {

    pc = '0';

    }

    for (var i =0, c = w - s.length; i < c; i++) {

    s = pc + s;

    }

    return s;

    };

     

    function toString(arr, isReverse) {

    if (typeof isReverse =='undefined') {

    isReverse = true;

    }

    var hi = arr[0], lo = arr[1];

    return padLeft((isReverse ? hi + lo * 0x100 : hi * 0x100 + lo).toString(16).toUpperCase(),4,'0');

    };

     

    /**

    * 16进制字符串异或处理

    *

    * @param str1

    * @param str2

    * @return

    */

    function stringXor(str1, str2) {

    if (!str1 && !str2) {

    return "";

    }

    if (!str1 && str2) {

    return str2;

    }

    if (str1 && !str2) {

    return str1;

    }

    var longStr;

    var shortStr;

    if (str1.length >= str2.length) {

    longStr = str1;

    shortStr = str2;

    } else {

    longStr = str2;

    shortStr = str1;

    }

    var count = parseInt(shortStr.length / 2);

    var leftCount = longStr.length - shortStr.length;

    var resultStr = "";

    if (leftCount > 0) {

    resultStr += longStr.substr(0, leftCount);

    }

    for (var i =0; i < count; i++) {

    var shortCharCode = parseInt(shortStr.substr(i *2, 2), 16);

    var longCharCode = parseInt(longStr.substr(leftCount + i *2, 2), 16);

    var resultCode = shortCharCode ^ longCharCode;

    var single = resultCode.toString(16);

    while (single.length < 2) single = "0".concat(single);

    resultStr += single;

    }

    return resultStr.toUpperCase();

    }

     

    /**

    * 指令两个16进制字符串异或处理

    *

    * @param command

    * @param secretKey

    * @return

    */

    function getSecretEncoding(command, secretKey) {

    if (!command || !secretKey) {

    return "";

    }

    var secretLength = secretKey.length;

    var length = parseInt(command.length / secretLength);

    console.log(`command(${command.length})/secretLength(${secretLength}) = ${length}`);

    var resultCmd = "";

    console.log(`secretKey(${secretKey.length}):${secretKey}`);

    for (var i =0; i < length; i++) {

    var part = command.substr(i * secretLength, secretLength);

    resultCmd += stringXor(part, secretKey);

    console.log(`part${i}:${stringXor(part, secretKey)}`);

    }

    var lastLen = command.length % secretLength;

    if (lastLen > 0) {

    console.log(`lastCMD:${command.substr(command.length - lastLen, lastLen)}`);

    console.log(`lastSecretKey:${secretKey.substr(0, lastLen)}`);

    var lastPart = command.substr(command.length - lastLen, lastLen);

    var lastCmd = stringXor(lastPart, secretKey.substr(0, lastLen));

    resultCmd += lastCmd;

    console.log(`lastPart:${lastCmd}`);

    }

    return resultCmd;

    }

    /**

    * 2、十六进制转换为字符串

    *主要使用 fromCharCode()方法,此方法将 Unicode 码转换为与之对应的字符。

    */

    function hexToString(str) {

    var val = "";

    var arr = str.split(",");

    for (var i =0; i < arr.length; i++) {

    val += arr[i].fromCharCode(i);

    }

    return val;

    }

     

    /**

    * 获取随机长度16进制字符串

    */

    function getRamNumber(length) {

    var result = '';

    for (var i =0; i < length; i++) {

    result += Math.floor(Math.random() * 16).toString(16);//获取0-15并通过toString转16进制

    }

    //默认字母小写,手动转大写

    return result.toUpperCase();//另toLowerCase()转小写

    }

     

    /**

    * 得到BCD码时间字符串

    *

    * @param datetime

    * @return

    */

    function getBCDTime(datetime, needWeek) {

    if (typeof datetime =='undefined') {

    datetime = new Date();

    }

    if (typeof needWeek =='undefined') {

    needWeek = true;

    }

    var year = datetime.getFullYear() - 2000; //获取年份,从2000年开始计算

    if (year < 0) year =0; // 不允许小于2000年的年份出现

    var month = datetime.getMonth() + 1;//获取月份 0-11 所以需要加1

    var day = datetime.getDate();//获取日

    var hour = datetime.getHours();//小时

    var minute = datetime.getMinutes();//分

    var second = datetime.getSeconds();//秒

    if (needWeek) {

    var dayOfWeek = datetime.getDay();//一周的第几天 0-6

    return formatNumber(year) + formatNumber(month) + formatNumber(day) + formatNumber(dayOfWeek)

    + formatNumber(hour) + formatNumber(minute) + formatNumber(second);// 得到BCD码的时间字符串

    } else {

    return formatNumber(year) + formatNumber(month) + formatNumber(day)

    + formatNumber(hour) + formatNumber(minute) + formatNumber(second);// 得到BCD码的时间字符串

    }

    }

    function formatNumber(n) {

    n = n.toString()

    return (n[1] ? n :'0' + n) + "";

    }

     

    /**

    * 判断一个字符串是否包含子串

    */

    function isContains(str, substr) {

    var strUp = str.toUpperCase();

    var substrUp = substr.toUpperCase()

    return new RegExp(substrUp).test(strUp);

    }

     

    /**

    * 去除字符串中特定的字符

    */

    function removeBytes(str, substr) {

    var items = str.split(substr)

    // 会得到一个数组,数组中包括利用o分割后的多个字符串(不包括o)

    var newStr = items.join("");

    return newStr

    // }

    }

     

    module.exports = {

    hexString2ArrayBuffer: hexString2ArrayBuffer,

    arrayBuffer2HexString: arrayBuffer2HexString,

    // getCRCCmd: getCRCCmd,

    getBCDTime: getBCDTime,

    stringToHex: stringToHex,

    stringXor: stringXor,

    getSecretEncoding: getSecretEncoding,

    hexToString: hexToString,

    getRamNumber: getRamNumber,

    isContains: isContains,

    removeBytes: removeBytes

    }

    听过baseBleApi接口调用输入参数直接可以对ble设备进行搜索发送链接

     

    傻瓜式调用,

    为了方便用户,这里进行了二级封装

    antsBleApi.js文件时为了方便用户调用的二级接口:

    var bleApi = require('baseBleApi.js');

    module.exports = {

    sendCommand: sendCommand

    }

    function sendCommand(params) {

    var defaults = {

    adviceId: "",

    sendCommend: "",

    onSuccessCallBack: function successCallBack(res) { },

    onFailCallBack: function failCallBack(res) { },

    onCompleteCallBack: function completeCallBack(res) { },

    services: ["xxxxx-xxxxxxxxx-xxxxx"],

    writeServiceUUID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",

    notifyServiceUUID: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",

    notifyCharacteristicUUID: "xxxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxx",

    writeCharacteristicUUID: "xxxx-xxxx-xxxx-xxxx-xxxx"

    }

    var setParams = Object.assign(defaults, params)

    bleApi.writeCommend(setParams);

    }

    此接口中service可以不写,但是adviceId,链接时必须写,,链接标志,writeServiceUUID,notifyServiceUUID,notifyCharacteristicUUID,writeCharacteristicUUID

    这几个参数是为了进行ble设备通信所用到的

     

    调用demo:

    openDoor: function () {

    var that = this

    progressUtils.showLoding();

    bleApi.sendCommand({

    deviceId: "xx:xx:xx:xx:xx:xx", sendCommend:"xxxxxxxxx", onSuccessCallBack: functiononSuccessCallBack(result) {

    wx.showToast({

    title: result,

    icon: '',

    image: '',

    duration: 1500,

    })

    console.log('result:' +result);

    }

    });

    展开全文
    parasoft 2019-04-17 10:10:06
  • 不管你是小程序小白还是ble小白,这个工具类都可以解决你的问题,使用极其简单,改下uuid就可以通信了,下面我简单介绍一下如何调用,不管你是使用我的代码,还是移植到自己的代码中都很简单,源码飞机票 如果帮您解决了...

    前言:

    20190429更新,新开发了一个库,如果你是android开发者你可能需要: 一个基于rxjava2的AndroidBle库-RxAndroidBluetooth

    2020/03/06更新,最近在使用中发现如果在页面进入时自动开启扫描的情况下,工具类没有提供很好的契机支持,所以我修改了一下部分代码,在bleStateListener方法中新增了一个状态用来监听蓝牙适配器初始化成功的回调,在该状态触发后调用者可开启扫描,此时扫描一定可用

    2020/03/09更新,补充2个问题,1.如果你在调试过程中发现断开连接的回调没有收到,你需要确定notify是否确定开启,开启之后才能接收到断开的回调,不知道小程序的文档为什么没有明确说明这个问题
    2.部分手机小程序搜索不到蓝牙,这是微信需要位置权限(6.0以上安卓手机)

    2020/03/20更新,最近主要调ios方面,在蓝牙方面的api上很多回调和android还是有一些差异的,调完之后也没有一一记录,我记忆比较深刻的是ios不能重复初始化适配器,否则会导致初始化函数无回调(概率大概为三分之一),我在论坛上看到有些人也遇到这个问题,不过我没有去告诉他们真相(哈哈),初始化适配器应该是全局唯一的,我们可以先获取适配器状态再根据状态决定是否初始化适配器以应对多个页面使用蓝牙功能,伪代码如下:

     wx.getBluetoothAdapterState({
        success: res => {
          //ios 蓝牙适配器没有初始化会走这里
          if (!res.available) {
            console.log('ios 蓝牙适配器没有初始化会走这里')
            _initBluetoothAdapter()
          } else {
            console.log('蓝牙适配器已初始化 android ios都会走这里')
          }
        },
        fail: err => {
          //android上未初始化蓝牙适配器会走这里
          if (err.errCode === 10000) {
            console.log('android上未初始化蓝牙适配器会走这里')
            _initBluetoothAdapter()
          }
        }
      })
    

    这样可以避免不同页面初始化的问题,当然我没有更新我的工具类,因为使用场景不同,过于复杂的工具类可能更难于理解,如果你在使用的过程中发现无法满足自己的需求,再修改代码
    2020/5/14更新,增加了版本号比较的函数
    2021/8/3更新,增加初始化蓝牙适配器代码

    /**
     *判断蓝牙适配器状态
     */
    function _initBleTools() {
    	wx.getBluetoothAdapterState({
        success: res => {
          //ios 蓝牙适配器没有初始化会走这里
          if (!res.available) {
            console.log('ios 蓝牙适配器没有初始化会走这里')
            _initBluetoothAdapter()
          } else {
            console.log('蓝牙适配器已初始化 android ios都会走这里')
          }
        },
        fail: err => {
          //android上未初始化蓝牙适配器会走这里
          if (err.errCode === 10000) {
            console.log('android上未初始化蓝牙适配器会走这里')
            _initBluetoothAdapter()
          }
        }
      })
    }
    
    /**
     * 初始化蓝牙适配器
     */
    function _initBluetoothAdapter(){
    	//初始化蓝牙适配器
      wx.openBluetoothAdapter({
        success: function(res) {
          console.log("初始化蓝牙适配器成功")
          //监听蓝牙适配器状态变化事件
          wx.onBluetoothAdapterStateChange(res => {
            if (res.discovering) {
              _this.bleStateListener(constants.STATE_SCANNING)
            } else {
              _this.bleStateListener(constants.STATE_SCANNED)
            }
          })
          //在后面的版本中我发现外部调用没有一个好的位置让调用者能够自动的发起扫描 添加这个方法就是让调用者在初始化适配器之后自动开启扫描
          _this.bleStateListener(constants.STATE_INIT_SUCCESS)
        },
        fail: function(err) {
          //在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下,调用 wx.openBluetoothAdapter 会返回错误(errCode=10001),表示手机蓝牙功能不可用
          if (err.errCode == 10001) {
            _this.bleStateListener(constants.STATE_CLOSE_BLE)
          }
        }
      })
    }
    

    下面是正文

    不管你是小程序小白还是ble小白,这个工具类都可以解决你的问题,使用极其简单,改下uuid就可以通信了,下面我简单介绍一下如何调用,不管你是使用我的代码,还是移植到自己的代码中都很简单,源码飞机票 如果帮您解决了燃眉之急请给个star吧…本人在小米,魅族,华为,苹果等机型测试过,都没有问题,为什么要这么封装,因为自己搜到的大部分博客都只是简单的介绍一下官方的文档,要么就是顺带拷贝了一些代码,有源码的呢又和ui等耦合很严重,有很多的Bug,对于小白来说太不友好了,而我这个堪称小白终结者


    写在最前:这些是我在准备写和写的过程中的一些需求:

    /** 
     * 
     * 只需要最简单的配置 傻瓜式使用 只要通过配置文件修改uuid 即可发送自己的数据至设备 √
     * 兼容ios android  √
     * 对当前用户的手机系统进行判断是否支持ble   √
     *   获取系统  及系统版本  √
     *   获取微信版本   √
     * 判断用户手机蓝牙是否打开  √
     * 错误码定义 √
     * 所有可变的配置抽取出来 统一配置参数  config文件编写√
     * 连接函数需要抽取出来   √
     * 扫描方法抽取 √
     * ble 操作过程中希望所有状态都抽取出来 通过一个函数来分发 而不是在代码中到处修改 √
     * 希望能对ui有最小的侵入 用户可以定义显示的ui 这边只采用最简单的显示在dialog中 √
     * 如果用户的场景不是手动点击连接 而是代码自动进行连接设备 可以调用_connectBle()传入device即可 √
     * 如果用户的场景不需要扫描 则不调用startScanBle()方法即可 这个方法只是断开当前正在连接的设备 开始扫描附近的外围设备 如果对你的逻辑有侵入 请自行修改 √
     * ios扫描同一个设备出现了两个  × 有瑕疵
     * 扫描时间配置  √
     * 将ble所有的操作都抽取为一个js  √
     *  1.之后也可以拷贝到其他地方使用,耦合低
     *  2.如果和业务逻辑都写在一起,代码很乱,阅读性差,不好维护
     *  3.每个用户可能自己的业务逻辑都不同,所以ble部分可能还需要自己再稍加修改,可以更快更容易定位到需要修改的地方
     *  4.更方便测试
     */
    

    写在开始,先看下运行效果:
    在这里插入图片描述
    再看下工程目录:
    在这里插入图片描述


    1.如果你是使用我的Demo,那么需要这些配置就可以发送数据了,为了怕有些小白找不到,所以我又粘了图,如果你不知道appid怎么申请,这…

    1. 配置appid 这个使用自己的
    2. 配置uuid ,在constants.js中修改
    3. 配置发送的数据 在constants.js中修改

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    只要在我图示的地方修改uuid为自己的uuid,将数据修改为你的设备能接收的数据就可以了,当然这个步骤是运行我的代码,如果你拷贝我的工具类拿到你i的工程中用,请看下一步


    2.如果你是只复制我的工具类的话,utils包必须全部拷贝,当然这些基础的东西就不多赘述了,比如你拷贝到你的项目中那么目录可能和我的不一致,自己改一下即可,这里主要说一下如何调用的我工具类

    1.首先你需要在你的实现类中Page中实现这三个方法

    1. writeListener
    2. notifyListener
    3. bleStateListener

    下面对三个方法进行说明

    writeListener:

     /**
       * 发送数据结果 true or false
       * 如果为false msg是失败原因
       */
      writeListener: function(result, msg) {
        //此处可以执行自己的逻辑 比如一些提示
        console.log(result ? '发送数据成功' : msg)
      },
    

    notifyListener

     /**
       * 接收数据 
       */
      notifyListener: function(data) {
        console.log('接收到数据')
        console.dir(data)
      },
    

    bleStateListener

    /**
       * ble状态监听
       */
      bleStateListener: function(state) {
        switch (state) {
          case constants.STATE_DISCONNECTED: //设备连接断开
            console.log('设备连接断开')
            break;
          case constants.STATE_SCANNING: //设备正在扫描
            console.log('设备正在扫描')
            break;
          case constants.STATE_SCANNED: //设备扫描结束
            console.log('设备扫描结束')
            break;
          case constants.STATE_CONNECTING: //设备正在连接
            console.log('设备正在连接')
            break;
          case constants.STATE_CONNECTED: //设备连接成功
            console.log('设备连接成功')
            break;
          case constants.STATE_CONNECTING_ERROR: //连接失败
            console.log('连接失败')
            break;
          case constants.STATE_NOTIFY_SUCCESS: //开启notify成功
            console.log('开启notify成功')
            break;
          case constants.STATE_NOTIFY_FAIL: //开启notify失败
            console.log('开启notify失败')
            break;
          case constants.STATE_CLOSE_BLE: //蓝牙未打开 关闭状态
    		 console.log('蓝牙未打开 关闭状态')
            break;
          case constants.STATE_NOTBLE_WCHAT_VERSION: //微信版本过低 不支持ble
     console.log('微信版本过低 不支持ble')
            break;
          case constants.STATE_NOTBLE_SYSTEM_VERSION: //系统版本过低 不支持ble
          console.log('系统版本过低 不支持ble')
            break;
          case constants.STATE_INIT_SUCCESS: //初始化蓝牙适配器成功 
            //tips:可以在此处调用扫描函数 蓝牙适配器初始化成功表示蓝牙在开启状态
            break;
        }
      },
    

    这三个方法理解为回调接口,内部细节可以看我的工具类

    上面说了实现这三个方法,下一步就是调用工具类中的方法来完成ble的初始化,扫描等操作,public方法如下:

    module.exports = {
      write,//写数据
      startScanBle,//开始扫描
      clear,//退出释放资源
      stopBluetoothDevicesDiscovery,//停止扫描
      connectBle,//连接设备
      initBle,//初始化蓝牙模块
      disconnect//断开连接
    }
    

    下面对每个方法进行说明(有执行顺序,并不是绝对顺序,但是你不能先发数据而不扫描设备吧?):
    1.initBle:初始化蓝牙适配器,并判断当前手机/微信版本是否支持Ble,调用如下,要放在生命周期函数内执行,结果将通过bleStateListener回调

      onLoad: function() {
        bletools.initBle(this)
      },
    

    注意bletools就是我的工具类,有导包的,这里说一下,下面就不多说了
    var bletools = require(’…/…/utils/bletools.js’);
    2.startScanBle,扫描附近蓝牙设备

     /**
       * 扫描蓝牙 
       */
      startScanBle {
        bletools.startScanBle({
          success:device => {
          }
        })
      },
    

    返回的device是对象而非数据,对象结构在微信小程序文档中是有的,这里不再赘述,看我的代码是通过数组来存储并显示的,当然你怎么显示或者不显示都可以按照自己的逻辑来

    3.stopBluetoothDevicesDiscovery:停止扫描,这个没啥说的,就是停止扫描呗

     bletools.stopBluetoothDevicesDiscovery()
    

    4.connectBle:连接ble设备

     bletools.connectBle(device)
    

    这里接收一个device对象,也就是第2步扫描到的device
    5.disconnect:断开当前连接

     bletools.disconnect()
    

    6.write:写数据到设备

      bletools.write(constants.testData1)
    

    constants.testData1是一个16进制数组,这个函数只接收16进制数组,Max长度为20字节
    7.clear:释放资源

    /**
       * 在页面退出时 销毁蓝牙适配器,在页面销毁的生命周期函数中我们一定要关闭蓝牙适配器释放资源
       */
      onUnload: function() {
        bletools.clear();
      },
    
    

    上述所有public方法的结果,或者开启的所有监听都会通过上面三个监听函数回调结果出来,比如设备扫描中,连接成功,断开连接,发送数据成功,接受的数据等等等…


    如果在使用过程中出现问题,请通过查看日志来解决,在文章的开始有图示一次完整的执行流程,如果发送数据失败,不一定是小程序的问题,请使用排除法来验证换一部手机,如果不是手机的问题请考虑使用第三方的ble工具来验证是否是硬件的问题,本人之前也写过一个Ble指令测试工具,是android的,你可以下载验证一下,博客地址,使用也很简单,下面列出一些可能导致出问题的地方以供排查

    1. uuid不对,这点尤为致命
    2. 连接不上,很大可能是手机兼容性有问题,请换一部手机试试
    3. 扫描不到,请确定硬件Ble不在休眠状态,且在广播状态
    4. 发送数据失败,请检查uuid/数据/ble是否还在连接
    5. 发送数据成功没有收到数据,请检查前面的notify监听已开启,特征变化监听已开启(我这里有log的)

    很简单啊 有没有?
    如果使用有啥问题,或者有什么bug,请给我留言,谢谢了,最后说下如果帮了你的忙,请给个star

    展开全文
    duo_shine 2018-11-27 18:22:37
  • 为了简化微信小程序环境下的蓝牙接入流程,经过线上正式项目一年的运行,发现BLE这块API许多坑,且难以移植复用,所以将它封装出来提高可维护性以及可移植性。 demo项目地址:https://github.com/arsize/ble 使用 ...

    为了简化微信小程序环境下的蓝牙接入流程,经过线上正式项目一年的运行,发现BLE这块API许多坑,且难以移植复用,所以将它封装出来提高可维护性以及可移植性。

    demo项目地址:https://github.com/arsize/ble

    使用

    安装Eventenitter

    npm install eventemitter2 --save

    引入
    在项目根目录utils文件夹下添加如下文件:ble.jsbleHandler.jstools.jserror.js
    完成上面步骤,就可以直接在小程序中使用蓝牙功能了。✨

    示例

    const emitter = new EventEmitter2();
    const ble = new BLE(blename, emitter)
    
    //注册监听事件,全局只有一个蓝牙信息通道
    ble.listen(res => {
      if (res.type == 'connect') {
        switch(res.data){
        	case "未打开适配器":
              break
            case "蓝牙已连接":
              break
            case ""
              break
        }
      }else if (res.type == "response") {
         console.log('收到设备消息响应:', res)
        //TODO
      }
    })
    
    ble.init()//蓝牙初始化,包含整个连接流程
    

    使用方法如上,很简单,只需要维护一个全局的ble实例,则可以进行蓝牙的各种功能操作。引入的那几个文件是用来干嘛的呢?
    大体上将蓝牙的连接、通讯、维护过程按功能的复杂程度分为三层:BLE、BLEHandler、Tool,ble更偏向用户层,blehandler提供一些流程性控制,tool则完全是封装的微信API,隔离一些繁复的工作,使代码看起来简洁一些。

    流程图

    源码解析

    BLE(提供面向用户的流程控制):

    import BLEHandler from "./bleHandler"
    
    class BLE extends BLEHandler {
        constructor(blename, emitter) {
            super(blename, emitter)
        }
        listen(callback) {
            // 蓝牙事件注册,打开channel
            this.emitter.removeAllListeners("channel")
            this.emitter.on("channel", callback)
        }
        removeListen() {
            // 移除所有蓝牙事件
            this.emitter.removeAllListeners("channel")
        }
        async init() {
            let flow = false
            // 打开蓝牙适配器状态监听
            this.onBLEConnectionStateChange()
            // 蓝牙适配器初始化
            await this.openAdapter()
            // 搜索蓝牙设备
            await this.startSearch()
            // 获取设备ID
            flow = await this.onBluetoothFound()
            // 停止搜索设备
            await this.stopSearchBluetooth()
            if (!flow) return
            // 连接蓝牙
            await this.connectBlue();
            // 获取serviceId
            await this.getBLEServices()
            // 设置特征值
            await this.getCharacteristics();
            // 订阅特征值
            await this.notifyBLECharacteristicValueChange()
            // 打开传输监听,等待设备反馈数据
            this.onBLECharacteristicValueChange()
        }
        // 发送指令
        async send(mudata, cmd) {
            let flow = await this.sentOrder(mudata, cmd)
            return flow
        }
        async close() {
            await this.closeBLEConnection()
            await this.closeBLEAdapter()
        }
    
    }
    
    export { BLE };
    展开全文
    zyh34163416 2021-05-18 14:47:36
  • 40KB dreams_deng 2020-07-06 17:45:22
  • 3星
    291KB leisheng2011 2019-02-01 17:10:11
  • 11KB weixin_42097533 2021-05-16 18:30:00
  • 最近老板总想开发微信小程序,然后我们公司又是倾向于智能硬件,所以直接还是上微信小程序BLE的开发demo。其实如果有过Android或者iOSble开发经验的人,开发微信小程序ble还是相当简单的,蓝牙的初始化、开启蓝牙、 ...

    最近老板总想开发微信小程序,然后我们公司又是倾向于智能硬件,所以直接还是上微信小程序BLE的开发demo。其实如果有过Android或者iOSble开发经验的人,开发微信小程序ble还是相当简单的,蓝牙的初始化、开启蓝牙、判断Android开启定位、开始扫描、判断连接、获取服务、获取特征值、订阅通知、写入数据等,都包含在一个按钮事件中,从上到下一气呵成。

    完成的方法代码如下:

    startBle: function() {

    wx.openBluetoothAdapter({ success: function(res) {

    console.log('ble初始化成功' + res)

    if (app.getPlatform() == 'android' && versionCompare(app.getsystem(), '10.0')) {

    wx.showToast({
    title: '安卓6.0以上需要开启GPS服务', duration: 2000

    })
    } else if (versionCompare('6.5.6', app.getVersion())) {

    wx.showModal({
    title: '提示',
    content: '当前微信版本过低,请更新至最新版本', showCancel: false

    }) }

    //开始搜索蓝牙 wx.startBluetoothDevicesDiscovery({

    success: function(res) { console.log('search', res)

    },
    fail: function(res) {

    console.log(res) wx.showModal({

    title: '提示',
    content: '请检查手机蓝牙是否打开',

    showCancel: false, success: function(res) {

    } })

    } })

    //发现设备 wx.getBluetoothDevices({

    success: function(res) {

    console.log('发现设备', res)

    } })

    //监听发现设备 wx.onBluetoothDeviceFound(function(devices) {

    console.log('发现设备1:', devices.devices) for (let i = 0; i < devices.devices.length; i++) {

    //检索指定设备
    if (devices.devices[i].name == 'qixiang_TS') {

    let deviceID = devices.devices[i].deviceId; console.log("deviceID" + deviceID) //蓝牙连接成功 停止搜索蓝牙 wx.stopBluetoothDevicesDiscovery({

    success: function(res) { console.log("停止蓝牙搜索") console.log(res)

    } })

    wx.createBLEConnection({ deviceId: deviceID, success: function(res) {

    console.log('蓝牙设备连接成功')

    wx.getBLEDeviceServices({
    deviceId: devices.devices[i].deviceId, success: function(res) {

    var service = res.services[1]
    var serviceId = service.uuid.substring(4, 8) if (serviceId == 'FFF0') {

    console.log('蓝牙设备Service = fff0') console.log(devices.devices[i].deviceId) console.log(service.uuid) wx.getBLEDeviceCharacteristics({

    deviceId: devices.devices[i].deviceId, serviceId: service.uuid,
    success: function(res) {

    if (res.characteristics[0].uuid == "0000FFF1-0000-1000-8000-00805F9B34FB") {//通知通道的

    uuid

    console.log('deviceID:', deviceID); console.log('service.uuid:', service.uuid); console.log('res.characteristics[0].uuid:',

    res.characteristics[0].uuid);

    wx.notifyBLECharacteristicValueChange({//订阅通知 state: true, // 启用 notify 功能

    deviceId: deviceID, serviceId: service.uuid, characteristicId:

    res.characteristics[0].uuid,
    success: function(res) {

    console.log('订阅notify成功')

    },
    fail: function(res) {

    console.log('订阅notify失败')

    },
    complete: function(res) {

    console.log('订阅notify完成') }

    })

    /**
    * 回调获取 设备发过来的数据 */

    wx.onBLECharacteristicValueChange(function(characteristic) {

    console.log('characteristic value comed:', characteristic.value)

    /**
    * 监听

    000FFF1-0000-1000-8000-00805F9B34FB中的结果 */

    }) }

    if (res.characteristics[1].uuid == "0000FFF2-0000-1000-8000-00805F9B34FB") {//写通道

    var hex = '063838D63B0000';

    var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h) {

    return parseInt(h, 16) }))

    console.log(typedArray)

    console.log([0xAA, 0x55, 0x04, 0xB1, 0x00, 0x00, 0xB5])

    var buffer1 = typedArray.buffer console.log(buffer1) wx.writeBLECharacteristicValue({//写方法

    deviceId: deviceID, serviceId: service.uuid, characteristicId:

    res.characteristics[1].uuid,
    value: buffer1,

    success: function(res) {//写成功 console.log(res)

    console.log('writeBLECharacteristicValue success', res.errMsg);

    },
    fail: function (res) {//写成功

    console.log(res) },

    complete: function (res) {//写完成 console.log(res)

    } })

    } },

    fail: function() { console.log('获取characteristic失败')

    } })

    }

    },
    fail: function(res) {

    wx.showModal({
    title: '设备Service信息',
    content: '蓝牙设备连接成功' + '\n' + '设备信息

    获取错误' + res.errMsg })

    } })

    },
    fail: function(res) {

    console.log('蓝牙设备连接失败,请稍后重试') wx.hideLoading()
    wx.showModal({

    title: '提示',
    content: '蓝牙设备连接失败,请稍后重试', duration: 2000

    }) },

    complete: function() { console.log('蓝牙设备连接完成') wx.hideLoading()

    } })

    } }

    }) }

    }) }

    哇咔咔,就这么愉快的完成了,如遇到其他问题可以留言交流。蓝牙问题都可以交流。

    展开全文
    wn2utt18 2020-05-21 15:12:04
  • 4星
    17KB weixin_38599537 2021-01-26 11:18:50
  • 13KB weixin_38744270 2019-09-25 18:57:55
  • qq_41667091 2019-12-12 00:01:14
  • 28KB weixin_38642285 2021-01-27 09:42:24
  • weixin_29479879 2021-01-14 07:47:18
  • 120KB weixin_38678773 2020-12-09 17:50:24
  • yebichao 2018-10-17 20:43:53
  • 23.37MB wang283006543 2020-09-02 11:58:28
  • 72KB weixin_38699830 2021-03-29 19:50:14
  • 4星
    7KB qq_36456827 2018-08-08 19:59:45
  • 3星
    4KB xin0089 2017-11-11 15:08:29
  • qq_18108159 2020-06-04 10:07:41
  • qq_38322527 2021-07-28 17:48:11
  • weixin_32797081 2021-06-03 00:00:36
  • gd6321374 2019-09-22 18:03:24
  • 4星
    118KB qq_21275565 2017-11-24 16:35:20
  • xh870189248 2019-10-01 16:09:16

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,104
精华内容 441
关键字:

微信小程序ble

微信小程序 订阅
友情链接: 用户数据拟合.zip