miniprogram: add iap mp for ble OTA

This commit is contained in:
royye62
2020-04-14 16:50:37 +08:00
parent e5c71448c7
commit 3500ccd27c
20 changed files with 1792 additions and 0 deletions

View File

@@ -0,0 +1,554 @@
/**
* 初始化蓝牙模块
*
* @return {Object} 调用结果
*/
function openBluetoothAdapter() {
return new Promise((resolve, reject) => {
wx.openBluetoothAdapter({
success(res) {
resolve(res)
},
fail(res) {
reject(res)
}
})
})
}
/**
* 关闭蓝牙模块
*
* @return {Object} 调用结果
*/
function closeBluetoothAdapter() {
return new Promise((resolve, reject) => {
wx.closeBluetoothAdapter({
complete(res) {
resolve(res)
}
})
})
}
/**
* 监听蓝牙状态
*
* @param {function} onBluetoothStateChange 函数对象,监听蓝牙状态变化的回调函数
* @return void
*/
function onBluetoothAdapterStateChange(onBluetoothStateChange) {
return new Promise((resolve) => {
wx.onBluetoothAdapterStateChange(function(res) {
// console.log('onBluetoothAdapterStateChange, now is', res)
onBluetoothStateChange(res)
})
resolve()
})
}
/**
* 启动搜索蓝牙设备功能
*
* @param {string} services 蓝牙服务
* @return void
*/
function startBluetoothDevicesDiscovery(services) {
return new Promise((resolve, reject) => {
wx.startBluetoothDevicesDiscovery({
services: services || [],
allowDuplicatesKey: false,
success(res) {
console.log("wx.startBluetoothDevicesDiscovery success")
resolve(res)
},
fail(res) {
console.log("wx.startBluetoothDevicesDiscovery fail")
reject(res)
}
})
})
}
/**
* 关闭搜索蓝牙设备功能
*
* @return void
*/
function stopBluetoothDevicesDiscovery() {
return new Promise((resolve, reject) => {
wx.stopBluetoothDevicesDiscovery({
complete(res) {
console.log("wx.stopBluetoothDevicesDiscovery success")
resolve()
}
})
})
}
/**
* 断开与低功耗蓝牙设备的连接
*
* @param {string} deviceId 蓝牙设备ID
* @return void
*/
function closeBLEConnection(deviceId) {
return new Promise((resolve, reject) => {
wx.closeBLEConnection({
deviceId,
success(res) {
console.log(`closeBLEConnection ${deviceId} success`, res)
},
fail(res) {
console.log(`closeBLEConnection ${deviceId} fail`, res)
},
complete(res) {
resolve()
}
})
})
}
/**
* 连接低功耗蓝牙设备
*
* @param {string} deviceId 蓝牙设备ID
* @return {Object} 调用结果
*/
function createBLEConnection(deviceId) {
return new Promise((resolve, reject) => {
wx.createBLEConnection({
deviceId: deviceId,
timeout: 5000, // TO_CHECK: 设置连接蓝牙超时时间
success: function(res) {
console.log(`createBLEConnection ${deviceId} success`, res)
resolve(res)
},
fail: function(res) {
console.log(`createBLEConnection ${deviceId} fail`, res);
reject(new Error(res.errMsg || 'wx.createBLEConnection fail'))
}
})
})
}
/**
* 监听低功耗蓝牙连接状态的改变事件
*
* @param {function} onStateChange 函数对象,连接状态变化的回调函数
* @return void
*/
function onBLEConnectionStateChange(onStateChange) {
return new Promise((resolve) => {
wx.onBLEConnectionStateChange(function(res) { // 该方法回调中可以用于处理连接意外断开等异常情况
// console.log(`onBLEConnectionStateChange device ${res.deviceId} state has changed, connected: ${res.connected}`)
onStateChange(res)
})
resolve()
})
}
/**
* 获取蓝牙设备所有服务
*
* @param {string} deviceId 蓝牙设备ID
* @return {Object} 调用结果
*/
function getBLEDeviceServices(deviceId) {
return new Promise((resolve, reject) => {
wx.getBLEDeviceServices({
deviceId: deviceId,
success: function(res) {
console.log(`wx.getBLEDeviceServices ${deviceId} success:`, res.services)
resolve(res.services)
},
fail(res) { // 获取蓝牙服务失败
console.log(`wx.getBLEDeviceServices ${deviceId} fail:`, res)
reject(res.errMsg || 'wx.getBLEDeviceServices fail')
}
})
})
}
/**
* 获取蓝牙设备某个服务中所有特征值
*
* @param {string} deviceId 蓝牙设备ID
* @param {string} serviceId 蓝牙服务ID
* @return {Object} 调用结果
*/
function getBLEDeviceCharacteristics(deviceId, serviceId) {
return new Promise((resolve, reject) => {
wx.getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: serviceId,
success(res) {
console.log(`wx.getBLEDeviceCharacteristics ${deviceId} ${serviceId} success:`, res.characteristics)
resolve(res.characteristics)
},
fail(res) { // 读取蓝牙特征值失败
console.log(`wx.getBLEDeviceCharacteristics ${deviceId} ${serviceId} fail`, res)
reject(res.errMsg || 'wx.getBLEDeviceCharacteristics fail')
},
})
})
}
/**
* 启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值
* 注:必须设备的特征值支持 notify 或者 indicate 才可以成功调用
*
* @param {string} deviceId 蓝牙设备ID
* @param {string} serviceId 蓝牙服务ID
* @param {string} notifyCharacteristicId 蓝牙特征值ID
* @return {Object} 调用结果
*/
function notifyBLECharacteristicValueChanged(deviceId, serviceId, notifyCharacteristicId) {
return new Promise((resolve, reject) => {
wx.notifyBLECharacteristicValueChanged({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: notifyCharacteristicId,
state: true,
success(res) {
console.log(`wx.notifyBLECharacteristicValueChanged ${deviceId} ${serviceId} ${notifyCharacteristicId} success`);
resolve(true)
},
fail(err) {
console.log(`wx.notifyBLECharacteristicValueChanged ${deviceId} ${serviceId} ${notifyCharacteristicId} fail`, err);
reject("启用蓝牙特征值notify功能失败")
}
})
})
}
/**
* 监听低功耗蓝牙设备的特征值变化事件
* 注:必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification
*
* @param {function} onMessage 函数对象,读数据的回调函数
* @return void
*/
function onBLECharacteristicValueChange(onMessage) {
var receivedData = null
return new Promise((resolve, reject) => {
wx.onBLECharacteristicValueChange(function(res) {
//{value: ArrayBuffer, deviceId: "D8:00:D2:4F:24:17", serviceId: "ba11f08c-5f14-0b0d-1080-007cbe238851-0x600000460240", characteristicId: "0000cd04-0000-1000-8000-00805f9b34fb-0x60800069fb80"}
onMessage(res.value)
})
resolve()
})
}
/**
* 向低功耗蓝牙设备特征值中写入二进制数据
* 注:必须设备的特征值支持 write 才可以成功调用
*
* @param {string} deviceId 蓝牙设备ID
* @param {string} serviceId 蓝牙服务ID
* @param {string} writeCharacteristicId 蓝牙特征值ID
* @param {string} payload 数据必须是ArrayBuffer类型
* @return {Object} 调用结果
*/
function writeBLECharacteristicValue(deviceId, serviceId, writeCharacteristicId, payload) {
return new Promise((resolve, reject) => {
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: writeCharacteristicId,
value: payload, // parameter.value should be ArrayBuffer
fail(res) {
console.log(`writeBLECharacteristicValue fail: ${deviceId} ${serviceId} ${writeCharacteristicId}`, res)
reject(res)
},
success(res) {
resolve(res)
}
})
})
}
/**
* 读取低功耗蓝牙设备的特征值的二进制数据值。
* 注:必须设备的特征值支持 read 才可以成功调用; 接口读取到的信息需要在 onBLECharacteristicValueChange 方法注册的回调中获取
*
* @param {string} deviceId 蓝牙设备ID
* @param {string} serviceId 蓝牙服务ID
* @param {string} readCharacteristicId 蓝牙特征值ID
* @return {Object} 调用结果
*/
function readBLECharacteristicValue(deviceId, serviceId, readCharacteristicId) {
return new Promise((resolve, reject) => {
wx.readBLECharacteristicValue({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: readCharacteristicId,
fail(res) {
console.log(`readBLECharacteristicValue fail: ${deviceId} ${serviceId} ${readCharacteristicId}`, res)
reject(res)
},
success(res) {
resolve(res)
}
})
})
}
/**
* 连接设备
*
* @param {string} deviceId 蓝牙设备ID
* @return {Object} 设备连接信息
*/
function connectDevice(deviceId) {
return closeBLEConnection(deviceId).then(() => {
// 断开重连需要间隔1s,否则会出现假连接成功
// 还有一种方式是 getConnectedBluetoothDevices对比已连接的蓝牙如果已连接直接跳到设备页面
return createBLEConnection(deviceId)
}).then(() => {
// 读取 BLE services
return getBLEDeviceServices(deviceId)
}).then(([deviceId, services]) => {
// 读取 BLE Characteristics
for (let i = 0; i < services.length; i++) {
if (services[i].isPrimary) { // 确定对应服务。这里使用第一个primary服务
let serviceId = services[i].uuid
return getBLEDeviceCharacteristics(deviceId, serviceId)
}
}
return Promise.reject(new Error('未找到蓝牙主服务'))
}).then(
// 必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 onBLECharacteristicValueChange 事件
([deviceId, serviceId, characteristics]) => {
let notifyCharacteristicId = null
let writeCharacteristicId = null
let readCharacteristicId = null
characteristics.forEach(function(item, index) {
if (item.properties.notify == true) {
notifyCharacteristicId = item.uuid
notifyBLECharacteristicValueChanged(deviceId, serviceId, item.uuid)
}
if (item.properties.write == true) {
writeCharacteristicId = item.uuid
}
if (item.properties.read == true) {
readCharacteristicId = item.uuid
}
})
let device = {
connected: true,
deviceId: deviceId,
serviceId: serviceId,
notifyCharacteristicId: notifyCharacteristicId,
writeCharacteristicId: writeCharacteristicId,
readCharacteristicId: readCharacteristicId,
}
return Promise.resolve(device)
}
)
}
/**
* 根据名称搜索设备
*
* @param {string} name 蓝牙设备名称
* @param {string} timeout 搜索超时时间单位ms
* @param {array} services 蓝牙设备的服务ID
* @return {string} deviceId 蓝牙设备ID
*/
function searchDeviceName(name, timeout, services = ["6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]) {
console.log("search begin", name)
let timer = null
let searchTimeout = new Promise((resolve, reject) => {
timer = setTimeout(function() {
console.log("searchDeviceName timeout", name)
stopBluetoothDevicesDiscovery()
reject(null)
}, timeout);
})
let search = Promise.resolve()
.then(() => {
return closeBluetoothAdapter()
})
.then(() => {
return openBluetoothAdapter()
})
.then(() => {
return startBluetoothDevicesDiscovery(services)
})
.then(() => {
return new Promise((resolve) => {
console.log("wx.onBluetoothDeviceFound start")
wx.onBluetoothDeviceFound(function(res) {
let foundName = res.devices[0].localName // TODO: localName or name?
if (foundName && foundName == name) {
console.log("searchDeviceName found:", name, res);
wx.offBluetoothDeviceFound(this)
clearTimeout(timer)
stopBluetoothDevicesDiscovery()
resolve(res.devices[0].deviceId)
}
})
})
})
return Promise.race([search, searchTimeout])
}
async function searchDevices(name, timeout, services = ["6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]) {
console.log("searchDevices", name)
let timer = null
let searchTimeout = new Promise((resolve, reject) => {
timer = setTimeout(function() {
console.log("searchDevices timeout", name)
stopBluetoothDevicesDiscovery()
reject(null)
}, timeout);
})
let search = Promise.resolve()
.then(() => {
return closeBluetoothAdapter()
})
.then(() => {
return openBluetoothAdapter()
})
.then(() => {
return startBluetoothDevicesDiscovery(services)
})
.then(() => {
return new Promise((resolve) => {
console.log("wx.onBluetoothDeviceFound start")
wx.onBluetoothDeviceFound(function(res) {
let foundName = res.devices[0].localName // TODO: localName or name?
if (foundName && foundName == name) {
console.log("searchDeviceName found:", name, res);
wx.offBluetoothDeviceFound(this)
clearTimeout(timer)
stopBluetoothDevicesDiscovery()
resolve(res.devices[0].deviceId)
}
})
})
})
return Promise.race([search, searchTimeout])
}
// function searchAndConnect(name, timeout, services = ["6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]) {
function searchAndConnect(name, timeout, services = []) {
return searchDeviceName(name, timeout, services).then(res => {
let devicesList = res
if (devicesList.length == 0) {
return Promise.reject(false)
}
let deviceId = devicesList[0].deviceId
return connectDevice(deviceId)
})
}
// 扫描设备
function scanDevicesForSometime(services, ms) {
startBluetoothDevicesDiscovery(services).then(res => {
console.log("wx.startBluetoothDevicesDiscovery success", res)
})
setTimeout(function() {
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("wx.stopBluetoothDevicesDiscovery success", res)
},
fail(e) {
console.log("wx.stopBluetoothDevicesDiscovery fail", res)
}
})
}, ms);
}
// 扫描设备
function connectFailAnalysis(deviceId) {
console.log("scanDevices ...")
let that = this
let found = false
let discovery = Promise.resolve().then(
() => {
return openBluetoothAdapter()
}
).then(
() => {
return startBluetoothDevicesDiscovery([])
// return startBluetoothDevicesDiscovery(["6E400001-B5A3-F393-E0A9-E50E24DCCA9E"])
}
).then(
() => {
let devicesList = []
return new Promise((resolve) => {
wx.onBluetoothDeviceFound(function(res) {
let name = res.devices[0].name
if (name != "") {
console.log("onBluetoothDeviceFound:", name, res);
devicesList.push(res.devices[0])
let foundDeviceId = res.devices[0].deviceId
console.log("found", foundDeviceId, deviceId)
// 尝试连接,读取等
if (foundDeviceId = deviceId) {
found = true
}
}
})
resolve()
})
}
)
let discoveryTimeout = new Promise(resolve => {
setTimeout(resolve, 10000);
}).then(res => {
console.log("discoveryTimeout")
return stopBluetoothDevicesDiscovery()
}).then(res => {
return new Promise(res => {
console.log("xxxx", found)
if (found) {
console.log("found", deviceId)
resolve(true)
} else {
console.log("not found", deviceId)
reject(false)
}
})
})
return Promise.race([discovery, discoveryTimeout])
}
module.exports = {
// 蓝牙适配器
closeBluetoothAdapter: closeBluetoothAdapter,
openBluetoothAdapter: openBluetoothAdapter,
onBluetoothAdapterStateChange: onBluetoothAdapterStateChange,
startBluetoothDevicesDiscovery: startBluetoothDevicesDiscovery,
stopBluetoothDevicesDiscovery: stopBluetoothDevicesDiscovery,
// BLE连接
closeBLEConnection: closeBLEConnection,
createBLEConnection: createBLEConnection,
onBLEConnectionStateChange: onBLEConnectionStateChange,
// BLE服务和特征值
getBLEDeviceServices: getBLEDeviceServices,
getBLEDeviceCharacteristics: getBLEDeviceCharacteristics,
notifyBLECharacteristicValueChanged: notifyBLECharacteristicValueChanged,
onBLECharacteristicValueChange: onBLECharacteristicValueChange,
// BLE读写
writeBLECharacteristicValue: writeBLECharacteristicValue,
readBLECharacteristicValue: readBLECharacteristicValue,
// wrapper
scanDevicesForSometime: scanDevicesForSometime,
searchDeviceName: searchDeviceName,
connectDevice: connectDevice,
searchAndConnect: searchAndConnect,
connectFailAnalysis: connectFailAnalysis,
}