您的当前位置:首页正文

【Taor微信小程序开发低功耗蓝牙使用】

2024-11-26 来源:个人技术集锦

首先需要获取用户授权

Taro.openBluetoothAdapter({
        success: (res) => {
            // 取消之前监听低功耗蓝牙连接状态的改变事件, 不传callback默认取消所有监听
            Taro.offBLEConnectionStateChange()
            // 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等
            Taro.onBLEConnectionStateChange(connectListener)
        },
        fail: (err) => {
            if (err.errMsg !== "openBluetoothAdapter:fail already opened") {
                console.error(err.errMsg)
                Taro.showToast({
                    title: "蓝牙初始化失败",
                    icon: 'error',
                    duration: 3000
                })
            }
        }
    })

搜寻附近的蓝牙外围设备

const startBluetoothDevicesDiscovery = async () => {
    if (_discoveryStarted) {
        return
    }
    _discoveryStarted = true

    // 清除上一次的计时器
    if (scanTimer) {
        clearTimeout(scanTimer)
        scanTimer = null
    }
	
	// 停止扫描
    scanTimer = setTimeout(() => {
        stopBluetoothDevicesDiscovery()
    }, scanTime)
    try {
        const res = await new Promise((resolve, reject) => {
            Taro.startBluetoothDevicesDiscovery({
                allowDuplicatesKey: false,
                success: (res) => {
                    console.log('开始搜寻附近的蓝牙外围设备', res);
                    // 监听寻找到新设备的事件
                    onBluetoothDeviceFound();
                    resolve(res);
                },
                fail: (err) => {
                    console.error(err.errMsg);
                    Taro.showToast({
                        title: '查找设备失败',
                        icon: 'error',
                        duration: 3000
                    });
                    reject(err);
                }
            });
        });
        _discoveryStarted = false;
        return res;
    } catch (error) {
        _discoveryStarted = false;
        if (scanTimer) {
            clearTimeout(scanTimer)
            scanTimer = null
        }
        throw error;
    }
}

监听寻找到新设备的事件

const onBluetoothDeviceFound = async () => {
    return new Promise((resolve, reject) => {
        devicesList.value = [];

        const handler = (res) => {
            const {devices} = res;
            devices.forEach(device => {
            	// 
                if (!device.name && device.localName) {
                    return;
                }
                // 过滤掉已经添加的设备
                const findIndex = devicesList.value.findIndex(item => item.deviceId === device.deviceId);
                if (findIndex === -1) {
                    devicesList.value.push(device);
                }
            });

            // 在这里可以根据需要决定resolve或reject
            resolve(devicesList.value); // 这里假设你希望返回devicesList.value
        };
        Taro.onBluetoothDeviceFound(handler);
    });
}

停止搜寻附近的蓝牙外围设备

// 停止搜寻附近的蓝牙外围设备
const stopBluetoothDevicesDiscovery = async () => {
    return new Promise((resolve, reject) => {
        Taro.stopBluetoothDevicesDiscovery({
            success: (res) => {
                console.log('停止搜寻附近的蓝牙外围设备', res);
                if (scanTimer) {
                    clearTimeout(scanTimer);
                    scanTimer = null;
                }
                _discoveryStarted = false;
                resolve(res);
            },
            fail: (err) => {
                console.error('停止搜寻附近的蓝牙外围设备 失败', err);
                reject(err);
            }
        });
    });
}

设备连接

const handleClickDevice = async (bleDevice) => {
    try {
        Taro.showLoading({title: '正在连接设备'})
        // 停止设备扫描
        await stopBluetoothDevicesDiscovery()
        if (!bleDevice.deviceId) {
            Taro.hideLoading()
            return;
        }

        if (activeBleDevice.value && activeBleDevice.value.connected) {
            await closeBLEConnection(activeBleDevice.value.deviceId)
        }
        const isCreateBLEConnection = await createBLEConnection(bleDevice.deviceId)
        if (!isCreateBLEConnection) {
            Taro.hideLoading()
            return;
        }
        Taro.hideLoading()
    } catch (error) {
        console.error(error)
    }
}

// 连接设备
async function createBLEConnection(deviceId: string) {
    console.log("【连接设备】", deviceId);
    return new Promise((resolve) => {
        Taro.createBLEConnection({
            deviceId,
            success: (res) => {
                console.log("连接设备 成功", res);
                resolve(true);
            },
            fail: (err) => {
                console.error("连接设备 失败", err);
                resolve(false); // 连接失败时返回 false
            },
        });
    });
}

断开设备连接

// 断开设备连接
async function closeBLEConnection(deviceId: string) {
    return new Promise((resolve) => {
        Taro.closeBLEConnection({
            deviceId,
            success: (res) => {
                console.log("断开设备连接 成功", res);
                resolve(true); // 成功时返回 true
            },
            fail: (err) => {
                console.error("断开设备连接 失败", err);
                resolve(false); // 断开失败时返回 false
            },
        });
    });
}

开始监听特征值变化

// 判断帧头和帧尾拼接完整的数据
function waitForDesiredValue() {
    return new Promise((resolve, reject) => {
        let characteristicValue = ""; // 用于拼接特征值
        const listener = function (res: any) {
            try {
                const resHexValue = arrayBufferToHex(res.value);
                console.log("特征值 resHexValue:", resHexValue);

                // 拼接特征值
                characteristicValue += resHexValue;

                // 在此处添加条件判断,例如,假设帧头帧尾分别是81828384,84838281就解决Promise并返回结果
                if (characteristicValue.startsWith("81828384") && characteristicValue.endsWith("84838281")) {
                    Taro.offBLECharacteristicValueChange(listener); // 停止监听
                    resolve(characteristicValue); // 解决 Promise 并返回特征值数据
                }
            } catch (e) {
                console.error("特征值解析失败", e);
                Taro.offBLECharacteristicValueChange(listener); // 停止监听
                reject(e.errMsg); // 拒绝 Promise 并传递错误消息给调用者
            }
        };

        // 开始监听特征值变化
        Taro.onBLECharacteristicValueChange(listener);
    });
}

写入数据

// 发送数据 !!!发送指令之前需要监听特征值的变化,从机响应的数据需要从监听特征值的变化的函数回调中获取
async function writeCharacter(deviceId: string, commandId: string, count: any = undefined) {
    return new Promise((resolve, reject) => {
        try {
            const base64 = Buffer.from(commandId, "hex").toString("base64");
            const arrayBuffer = Taro.base64ToArrayBuffer(base64);

            // 调用waitForDesiredValue函数来等待满足条件的特征值, 这个函数需要根据自己业务和蓝牙协议实现
            waitForDesiredValue()
                .then((result) => {
                    // 在这里处理满足条件的特征值
                    resolve(result); // 解决 Promise 并将特征值传递给调用者
                })
                .catch((error) => {
                    console.error("等待特征值失败", error);
                    reject(error.errMsg); // 拒绝 Promise 并传递错误消息给调用者
                });

            Taro.getBLEDeviceServices({
                deviceId: deviceId,
                success: function (res) {
                    const service = res.services.find(
                        item => item.uuid.toUpperCase() === writeServiceUUID);
                    if (!service) {
                        console.log("没有找到该服务", res);
                        reject("没有找到该服务"); // 拒绝 Promise 并传递错误消息给调用者
                        return;
                    }
                    const servicesUUID = service.uuid;
                    // 获取蓝牙设备某个服务中所有特征值(characteristic)
                    Taro.getBLEDeviceCharacteristics({
                        deviceId: deviceId,
                        serviceId: servicesUUID,
                        success: function () {
                            Taro.writeBLECharacteristicValue({
                                deviceId: deviceId,
                                serviceId: writeServiceUUID,
                                characteristicId: writeCharacteristicUUID,
                                value: arrayBuffer,
                                success: function (res) {
                                    console.log("发送数据成功", res.errMsg);
                                    // 不要在这里解决 Promise,因为特征值变化时才应该解决
                                },
                                fail: function (res) {
                                    console.log("发送数据失败", res.errMsg);
                                    reject(res.errMsg); // 拒绝 Promise 并传递错误消息给调用者
                                }
                            });
                        }
                    });
                },
                fail: function (res) {
                    console.log("获取蓝牙设备所有服务 失败", res.errMsg);
                    reject(res.errMsg); // 拒绝 Promise 并传递错误消息给调用者
                }
            });
        } catch (e) {
            console.log("发送数据失败", e);
            reject(e.errMsg); // 拒绝 Promise 并传递错误消息给调用者
        }
    });
}

!!!微信小程序原生API的调用同上

显示全文