smartmeter-app/utils/blufi/crypto/lib/blelib.js
2024-08-31 18:01:17 +08:00

404 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function BLEDevice(arg) {
this.deviceId = "";
this.serviceId = "";
this.debug = arg ? (arg['debug'] || false) : false;
this.connectTimeout = arg ? (arg['connectTimeout'] || 10000) : 10000;
this.onBLECharacteristicValueChange = {}
};
/**
* 日志输出
*
* @param {msg} String
* 输出的信息
* @param {Array} args
* 辅助输出信息
*/
BLEDevice.prototype.log = function (msg, ...args) {
if (this.debug) {
console.log(msg, ...args)
}
};
BLEDevice.prototype.setStateCallBack = function (cb) {
wx.onBluetoothAdapterStateChange((res) => {
cb(res);
});
}
/**
* 初始化蓝牙模块
*
* @return
* 返回蓝牙模块Promise
*/
BLEDevice.prototype.openBluetoothAdapter = function() {
return new Promise((resolve, reject) => {
wx.openBluetoothAdapter({
success: (res) => {
this.log("openBluetoothAdapter", res);
resolve(res);
},
fail: (res) => {
this.log("openBluetoothAdapter failed", res)
reject(res);
}
})
})
};
/**
* 关闭蓝牙模块
*/
BLEDevice.prototype.closeBluetoothAdapter = function() {
wx.closeBluetoothAdapter();
};
/**
* 获取本机蓝牙适配器状态
*/
BLEDevice.prototype.getBluetoothAdapterState = function () {
wx.getBluetoothAdapterState({
success: (res) => {
if (res.discovering) {
this.onBluetoothDeviceFound()
} else if (res.available) {
setTimeout(()=>{
this.startBluetoothDevicesDiscovery(state.servicesId, state.key);
},500)
}
}
})
};
/**
* 开始搜寻附近的蓝牙外围设备
*
* @param {String} servicesId
* 要搜索的蓝牙设备主服务的uuid列表
* @param {Function} cb
* 发现设备后的回调
* 若发现成功参数success为truefoundDevices发现的设备列表
* 若发现失败参数success为false
* @return
* 返回搜索蓝牙设备Promise
*/
BLEDevice.prototype.startBluetoothDevicesDiscovery = function (servicesId, cb) {
let foundDevices = [];
wx.onBluetoothDeviceFound((res) => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return;
}
const idx = inArray(foundDevices, 'deviceId', device.deviceId)
if (idx === -1) {
foundDevices.push(device)
} else {
foundDevices[idx] = device
}
this.log("onBluetoothDeviceFound", foundDevices);
cb({ success: true, foundDevices: foundDevices});
})
})
wx.startBluetoothDevicesDiscovery({
services: servicesId,
allowDuplicatesKey: true,
success: (res) => {
this.log("startBluetoothDevicesDiscovery", res);
},
fail: (res) => {
cb({ success: false });
}
})
};
/**
* 停止搜寻附近的蓝牙外围设备
*/
BLEDevice.prototype.stopBluetoothDevicesDiscovery = function () {
wx.stopBluetoothDevicesDiscovery();
};
/**
* 连接低功耗蓝牙设备
*
* @param {String} deviceId
* 连接设备的ID
*
* @return
* 返回设备连接的Promise
*/
BLEDevice.prototype.createBLEConnection = function (deviceId) {
this.deviceId = deviceId;
return new Promise((resolve, reject) => {
wx.createBLEConnection({
deviceId: this.deviceId,
success: (res) => {
this.log("createBLEConnection", res)
this.getBLEDeviceServices()
.then(() => {
resolve();
}).catch((res) => {
reject(res);
this.closeBLEConnection();
})
},
fail: (res) => {
this.log("createBLEConnection failed", res)
reject(res)
}
})
this.stopBluetoothDevicesDiscovery();
setTimeout(() => {
reject('Connect timeout');
this.closeBLEConnection();
}, this.connectTimeout);
})
};
/**
* 断开与低功耗蓝牙设备的连接
*/
BLEDevice.prototype.closeBLEConnection = function () {
wx.closeBLEConnection({
deviceId: this.deviceId,
})
};
/**
* 获取蓝牙设备的所有服务
*
* @param {String} findServicesUUID
* 要查找的主服务uuid
*
* @param {Number} findServicesIndex
* 开始查找的位置
*
* @return
* 返回获取服务的Promise
*/
BLEDevice.prototype.getBLEDeviceServices = function () {
return new Promise((resolve, reject) => {
wx.getBLEDeviceServices({
deviceId: this.deviceId,
success: (res) => {
let total = res.services.length
for (let i = 0; i < res.services.length; i++) {
this.log("getBLEDeviceServices", res.services[i]);
this.getBLEDeviceCharacteristics(res.services[i].uuid)
.then(() => {
total --;
if (total === 0) {
resolve();
}
})
.catch(res => {
reject(res);
})
}
},
fail: (res) => {
reject(res);
}
})
})
};
/**
* 获取蓝牙设备某个服务中所有特征值
*
* @param {String} serviceId
* 要查找特征的service uuid
*
* @return
* 返回服务特征值的Promise
*/
BLEDevice.prototype.getBLEDeviceCharacteristics = function (serviceId) {
return new Promise((resolve, reject) => {
wx.getBLEDeviceCharacteristics({
deviceId: this.deviceId,
serviceId: serviceId,
success: (res) => {
resolve(res);
for (let i = 0; i < res.characteristics.length; i++) {
this.log("getBLEDeviceCharacteristics", i, res.characteristics[i]);
let item = res.characteristics[i];
if (item.properties.read) {
this.log("可读:", res.characteristics[i]);
}
if (item.properties.write) {
this.log("可写:", res.characteristics[i]);
}
if (item.properties.notify || item.properties.indicate) {
this.log("可订阅", res.characteristics[i]);
}
}
},
fail: (res) => {
reject(res);
},
complete: (res) => {
}
})
})
};
/**
* 读取低功耗蓝牙设备的特征值的二进制数据值
*
* @param {String} serviceId
* 蓝牙可订阅服务的uuid
*
* @param {String} readCharacteristicId
* 蓝牙可读特征值的uuid
*
* @param {Function} callback
* 特征变化的回调函数
*/
BLEDevice.prototype.readBLECharacteristicValue = function (serviceId, readCharacteristicId, callback) {
wx.onBLECharacteristicValueChange((characteristic) => {
this.log("onBLECharacteristicValueChange", characteristic.value)
let cb = this.onBLECharacteristicValueChange[readCharacteristicId]
if (cb) {
cb(characteristic)
}
})
return new Promise((resolve, reject) => {
wx.readBLECharacteristicValue({
deviceId: this.deviceId,
serviceId: serviceId,
characteristicId: readCharacteristicId,
success: (res) => {
resolve(res)
this.log('readBLECharacteristicValue', res);
this.onBLECharacteristicValueChange[readCharacteristicId] = callback;
},
fail: (res) => {
reject(res)
}
})
})
};
/**
* 向低功耗蓝牙设备特征值中写入二进制数据
*
* @param {String} writeCharacteristicId
* 蓝牙可写特征值的uuid
*
* @param {ArrayBuffer} buffer
* 特征值对应的二进制值
*/
BLEDevice.prototype.writeBLECharacteristicValue = function (serviceId, writeCharacteristicId, buffer) {
// // 向蓝牙设备发送一个0x00的16进制数据
this.log("writeBLECharacteristicValue buffer", buffer);
wx.writeBLECharacteristicValue({
deviceId: this.deviceId,
serviceId: serviceId,
characteristicId: writeCharacteristicId,
value: buffer,
success: (res) => {
this.log('writeBLECharacteristicValue', res);
}
})
};
/**
* 启用低功耗蓝牙设备特征值变化时的notify功能订阅特征值
*
* @param {String} serviceId
* 蓝牙可订阅服务的uuid
*
* @param {String} notifyCharacteristicId
* 蓝牙可订阅特征值的uuid
*
* @param {Function} callback
* 特征变化的回调函数
*/
BLEDevice.prototype.notifyBLECharacteristicValueChange = function (serviceId, notifyCharacteristicId, callback) {
wx.onBLECharacteristicValueChange((characteristic) => {
this.log("onBLECharacteristicValueChange", characteristic.value)
let cb = this.onBLECharacteristicValueChange[notifyCharacteristicId]
if (cb) {
cb(characteristic)
}
})
return new Promise((reslove, reject) => {
wx.notifyBLECharacteristicValueChange({
deviceId: this.deviceId,
serviceId: serviceId,
characteristicId: notifyCharacteristicId,
state: true,
success: (res) => {
reslove(res)
this.log('notifyBLECharacteristicValueChange', res);
this.onBLECharacteristicValueChange[notifyCharacteristicId] = callback
},
fail: (res) => {
reject(res)
}
})
})
};
/**
* 关闭低功耗蓝牙设备特征值变化时的notify功能订阅特征值
*
* @param {String} serviceId
* 蓝牙可订阅服务的uuid
*
* @param {String} notifyCharacteristicId
* 蓝牙可订阅特征值的uuid
*/
BLEDevice.prototype.unNotifyBLECharacteristicValueChange = function (serviceId, notifyCharacteristicId) {
return new Promise((resolve, reject) => {
delete this.onBLECharacteristicValueChange[notifyCharacteristicId]
wx.notifyBLECharacteristicValueChange({
deviceId: this.deviceId,
serviceId: serviceId,
characteristicId: notifyCharacteristicId,
state: false,
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
}
})
})
}
const inArray = (arr, key, val) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === val) {
return i;
}
}
return -1;
};
/**
* ArrayBuffer转16进度字符串示例
*/
const ab2hex = (buffer) => {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2);
}
)
return hexArr.join('');
};
module.exports = BLEDevice