Name: wx-simple-bluetooth
Anwendbare Plattformen: WeChat-Applet
Bluetooth: Bluetooth Low Energy
Projektversion: 2.0.1
Dieses Projekt besteht aus drei Ebenen: Bluetooth-Verbindung, Bluetooth-Protokollkommunikation, Statusabonnement und Benachrichtigung. Es kann die Bluetooth-Entwicklung Ihres eigenen Miniprogramms problemlos anpassen. Die Hauptfunktionen sind wie folgt:
!!!Sie müssen zuerst die erweiterte Kompilierung der WeChat-Entwicklungstools aktivieren!!!
这个项目从蓝牙连接、蓝牙协议通信、状态订阅及通知三个层面进行设计,可以很方便的定制您自己的小程序的蓝牙开发。主要功能如下
:
Folgendes ist der Fall, wenn die Bluetooth-Funktion, GPS- und WeChat-Ortungsberechtigungen auf dem Mobiltelefon aktiviert sind:
getAppBLEManager.connect()
werden alle 350ms
automatisch umliegende Bluetooth-Geräte gescannt und innerhalb dieser Zeit eine Verbindung zu dem Gerät mit dem stärksten Signal hergestellt.uuid
Liste des service
und die entsprechende für die Kommunikation verwendete Dienst-ID festlegen. Sie können auch zusätzliche Bluetooth-Gerätenamen hinzufügen, um die Geräte weiter zu filtern.注意:目前在发送数据时大于20包的数据会被裁剪为20包
. (有些蓝牙连接问题是微信兼容或是手机问题,目前是无法解决的。如错误码10003以及部分华为手机蓝牙连接或重连困难。如果您有很好的解决方案,还请联系我,十分感谢)
lb-example-bluetooth-manager.js
.Basierend auf dieser Überlegung weist dieses Framework daher die folgenden Einschränkungen auf:
- Um das Framework normal nutzen zu können, muss die Vereinbarung entsprechend dem vereinbarten Vereinbarungsformat formuliert werden.
- Die maximale Datenanzahl in einem Paket des Protokolls beträgt 20 Bytes. Das Framework unterstützt keine Protokollformate, die größer als 20 Byte sind. Sollten die Daten das Limit überschreiten, empfiehlt es sich, diese auf mehrere Sendungen aufzuteilen.
- Es wird empfohlen, Schreibvorgänge im seriellen Modus durchzuführen.
- Es wird empfohlen, zunächst die offizielle Bluetooth-Dokumentation des Miniprogramms zu lesen, um das Verständnis für die Verwendung des Frameworks zu erleichtern.
协议约定格式:[...命令字之前的数据(非必需), 命令字(必需), ...有效数据(非必需 如控制灯光发送255,255,255), 有效数据之后的数据(非必需 如协议结束标志校、验位等)
协议格式示例:[170(帧头), 10(命令字), 1(灯光开启),255,255,255(三个255,白色灯光),233(协议结束标志,有的协议中没有这一位),18(校验位,我胡乱写的)]
有效数据是什么:
在刚刚的这个示例中,帧头、协议结束标志是固定的值,校验位是按固定算法生成的,这些不是有效数据。而1,255,255,255这四个字节是用于控制蓝牙设备的,属于有效数据。
Wenn dieses Projekt hilfreich ist, hoffe ich, ihm auf GitHub einen Stern zu geben!
modules
unter dem Projekt in Ihr Projekt import Toast from "../../view/toast";
import UI from './ui';
import {ConnectState} from "../../modules/bluetooth/lb-bluetooth-state-example";
import {getAppBLEProtocol} from "../../modules/bluetooth/lb-example-bluetooth-protocol";
import {getAppBLEManager} from "../../modules/bluetooth/lb-example-bluetooth-manager";
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
connectState: ConnectState.UNAVAILABLE
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.ui = new UI(this);
console.log(app);
//监听蓝牙连接状态、订阅蓝牙协议接收事件
//多次订阅只会在最新订阅的函数中生效。
//建议在app.js中订阅,以实现全局的事件通知
getAppBLEManager.setBLEListener({
onConnectStateChanged: async (res) => {
const {connectState} = res;
console.log('蓝牙连接状态更新', res);
this.ui.setState({state: connectState});
switch (connectState) {
case ConnectState.CONNECTED:
//在连接成功后,紧接着设置灯光颜色和亮度
//发送协议,官方提醒并行调用多次会存在写失败的可能性,所以建议使用串行方式来发送
await getAppBLEProtocol.setColorLightAndBrightness({
brightness: 100,
red: 255,
green: 0,
blue: 0
});
break;
default:
break;
}
},
/**
* 接收到的蓝牙设备传给手机的有效数据,只包含你最关心的那一部分
* protocolState和value具体的内容是在lb-example-bluetooth-protocol.js中定义的
*
* @param protocolState 蓝牙协议状态值,string类型,值是固定的几种,详情示例见:
* @param value 传递的数据,对应lb-example-bluetooth-protocol.js中的{effectiveData}字段
*/
onReceiveData: ({protocolState, value}) => {
console.log('蓝牙协议接收到新的 protocolState:', protocolState, 'value:', value);
}
});
//这里执行连接后,程序会按照你指定的规则(位于getAppBLEManager中的setFilter中指定的),自动连接到距离手机最近的蓝牙设备
getAppBLEManager.connect();
},
/**
* 断开连接
* @param e
* @returns {Promise<void>}
*/
async disconnectDevice(e) {
// closeAll() 会断开蓝牙连接、关闭适配器
await getAppBLEManager.closeAll();
this.setData({
device: {}
});
setTimeout(Toast.success, 0, '已断开连接');
},
/**
* 连接到最近的设备
*/
connectHiBreathDevice() {
getAppBLEManager.connect();
},
async onUnload() {
await getAppBLEManager.closeAll();
},
});
setFilter
-Funktionsparameter und Scan-Filterregeln fest (optional). Die Datei befindet sich unter ./modules/bluetooth/lb-example-bluetooth-manager.js
import {LBlueToothManager} from "./lb-ble-common-connection/index";
import {getAppBLEProtocol} from "./lb-example-bluetooth-protocol";
/**
* 蓝牙连接方式管理类
* 初始化蓝牙连接时需筛选的设备,重写蓝牙连接规则
*/
export const getAppBLEManager = new class extends LBlueToothManager {
constructor() {
super();
//setFilter详情见父类
super.setFilter({
services: ['0000xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'],//必填
targetServiceArray: [{
serviceId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',//必填
writeCharacteristicId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxE',//必填
notifyCharacteristicId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxF',//必填
readCharacteristicId: '',//非必填
}],
targetDeviceName: '目标蓝牙设备的广播数据段中的 LocalName 数据段,如:smart-voice',//非必填,在判断时是用String.prototype.includes()函数来处理的,所以targetDeviceName不必是全称
scanInterval: 350//扫描周围设备,重复上报的时间间隔,毫秒制,非必填,默认是350ms
});
super.initBLEProtocol({bleProtocol: getAppBLEProtocol});
//setMyFindTargetDeviceNeedConnectedFun函数调用可选,不实现过滤规则框架会按默认规则执行
super.setMyFindTargetDeviceNeedConnectedFun({
/**
* 重复上报时的过滤规则,并返回过滤结果
* 在执行完该过滤函数,并且该次连接蓝牙有了最终结果后,才会在下一次上报结果回调时,再次执行该函数。
* 所以如果在一次过滤过程中或是连接蓝牙,耗时时间很长,导致本次连接结果还没得到,就接收到了下一次的上报结果,则会忽略下一次{scanFilterRuler}的执行。
* 如果不指定这个函数,则会使用默认的连接规则
* 默认的连接规则详见 lb-ble-common-connection/utils/device-connection-manager.js的{defaultFindTargetDeviceNeedConnectedFun}
* @param devices {*}是wx.onBluetoothDeviceFound(cb)中返回的{devices}
* @param targetDeviceName {string}是{setFilter}中的配置项
* @returns targetDevice 最终返回对象{targetDevice},是数组{devices}其中的一个元素;{targetDevice}可返回null,意思是本次扫描结果未找到指定设备
*/
scanFilterRuler: ({devices, targetDeviceName}) => {
console.log('执行自定义的扫描过滤规则');
const tempFilterArray = [];
for (let device of devices) {
if (device.localName?.includes(targetDeviceName)) {
tempFilterArray.push(device);
}
}
if (tempFilterArray.length) {
const device = tempFilterArray.reduce((pre, cur) => {
return pre.RSSI > cur.RSSI ? pre : cur;
});
return {targetDevice: device};
}
return {targetDevice: null};
}
})
}
/**
* 获取本机蓝牙适配器状态
* @returns {Promise<*>} 返回值见小程序官网 wx.getBluetoothAdapterState
*/
async getBLEAdapterState() {
return await super.getBLEAdapterState();
}
/**
* 获取最新的蓝牙连接状态
* @returns {*}
*/
getBLELatestConnectState() {
return super.getBLELatestConnectState();
}
}();
Die Datei befindet sich unter ./modules/bluetooth/lb-ble-example-protocol-body
//send-body.js
import {IBLEProtocolSendBody} from "../lb-ble-common-protocol-body/index";
import {HexTools} from "../lb-ble-common-tool/index";
/**
* 组装蓝牙协议发送数据示例
* 该框架的蓝牙协议必须按照约定格式来制定,最多20个字节
*/
export default class SendBody extends IBLEProtocolSendBody {
getDataBeforeCommandData({command, effectiveData} = {}) {
//有效数据前的数据 该示例只返回了帧头110
return [110];
}
getDataAfterEffectiveData({command, effectiveData} = {}) {
//协议结束标志
const endFlag = 233;
//该示例中checkSum的生成规则是计算协议从第0个元素累加到结束标志
let checkSum = endFlag + HexTools.hexToNum(command);
for (let item of this.getDataBeforeCommandData()) {
checkSum += item;
}
for (let item of effectiveData) {
checkSum += item;
}
//生成有效数据之后的数据
return [endFlag, checkSum];
}
}
//receive-body.js
import {IBLEProtocolReceiveBody} from "../lb-ble-common-protocol-body/index";
/**
* 组装蓝牙协议接收数据示例
* 该框架的蓝牙协议必须按照约定格式来制定,最多20个字节
*/
export default class ReceiveBody extends IBLEProtocolReceiveBody {
constructor() {
//commandIndex 命令字位置索引
//effectiveDataStartIndex 有效数据开始索引,比如:填写0,{getEffectiveReceiveDataLength}中返回20,则会在{LBlueToothProtocolOperator}的子类{getReceiveAction}实现中,在参数中返回所有数据
super({commandIndex: 1, effectiveDataStartIndex: 0});
}
/**
* 获取有效数据的字节长度
* 该长度可根据接收到的数据动态获取或是计算,或是写固定值均可
* 有效数据字节长度是指,在协议中由你的业务规定的具有特定含义的值的总字节长度
* 有效数据更多的说明,以及该长度的计算规则示例,见 IBLEProtocolReceiveBody 类的 {getEffectiveReceiveData}函数
*
* @param receiveArray 接收到的一整包数据
* @returns {number} 有效数据的字节长度
*/
getEffectiveReceiveDataLength({receiveArray}) {
return 20;
}
}
Befindet sich in modules/bluetooth/lb-example-bluetooth-protocol.js
import {LBlueToothProtocolOperator} from "./lb-ble-common-protocol-operator/index";
import SendBody from "./lb-ble-example-protocol-body/send-body";
import ReceiveBody from "./lb-ble-example-protocol-body/receive-body";
import {ProtocolState} from "./lb-bluetooth-state-example";
/**
* 蓝牙协议管理类
* 在这个类中,以配置的方式来编写读操作和写操作
* 配置方式见下方示例
*/
export const getAppBLEProtocol = new class extends LBlueToothProtocolOperator {
constructor() {
super({protocolSendBody: new SendBody(), protocolReceiveBody: new ReceiveBody()});
}
/**
* 写操作(仅示例)
*/
getSendAction() {
return {
/**
* 0x01:设置灯色(写操作)
* @param red 0x00 - 0xff
* @param green 0x00 - 0xff
* @param blue 0x00 - 0xff
* @returns {Promise<void>}
*/
'0x01': async ({red, green, blue}) => {
return await this.sendProtocolData({command: '0x01', effectiveData: [red, green, blue]});
},
/**
* 0x02:设置灯亮度(写操作)
* @param brightness 灯亮度值 0~100 对应最暗和最亮
* @returns {Promise<void>}
*/
'0x02': async ({brightness}) => {
//data中的数据,填写多少个数据都可以,可以像上面的3位,也可以像这条6位。你只要能保证data的数据再加上你其他的数据,数组总长度别超过20个就行。
return await this.sendProtocolData({command: '0x02', effectiveData: [brightness, 255, 255, 255, 255, 255]});
},
}
}
/**
* 读操作(仅示例)
* {dataArray}是一个数组,包含了您要接收的有效数据。
* {dataArray}的内容是在lb-ble-example-protocol-body.js中的配置的。
* 是由您配置的 dataStartIndex 和 getEffectiveReceiveDataLength 共同决定的
*/
getReceiveAction() {
return {
/**
* 获取设备当前的灯色(读)
* 可return蓝牙协议状态protocolState和接收到的数据effectiveData,
* 该方法的返回值,只要拥有非空的protocolState,该框架便会同步地通知前端同protocolState类型的消息
* 当然是在你订阅了setBLEListener({onReceiveData})时才会在订阅的地方接收到消息。
*/
'0x10': ({dataArray}) => {
const [red, green, blue] = dataArray;
return {protocolState: ProtocolState.RECEIVE_COLOR, effectiveData: {red, green, blue}};
},
/**
* 获取设备当前的灯亮度(读)
*/
'0x11': ({dataArray}) => {
const [brightness] = dataArray;
return {protocolState: ProtocolState.RECEIVE_BRIGHTNESS, effectiveData: {brightness}};
},
/**
* 接收到设备主动发送的灯光关闭消息
* 模拟的场景是,用户关闭了设备灯光,设备需要主动推送灯光关闭事件给手机
*/
'0x12': () => {
//你可以不传递effectiveData
return {protocolState: ProtocolState.RECEIVE_LIGHT_CLOSE};
},
/**
* 接收到蓝牙设备的其他一些数据
*/
'0x13': ({dataArray}) => {
//do something
//你可以不返回任何值
}
};
}
/**
* 设置灯亮度和颜色
* @param brightness
* @param red
* @param green
* @param blue
* @returns {Promise<[unknown, unknown]>}
*/
async setColorLightAndBrightness({brightness, red, green, blue}) {
//发送协议,小程序官方提醒并行调用多次会存在写失败的可能性,所以建议使用串行方式来发送,哪种方式由你权衡
//但我这里是并行发送了两条0x01和0x02两条协议,仅演示用
return Promise.all([this.sendAction['0x01']({red, green, blue}), this.sendAction['0x02']({brightness})]);
}
}();
Die Datei befindet sich in modules/bluetooth/lb-bluetooth-state-example.js
import {CommonConnectState, CommonProtocolState} from "./lb-ble-common-state/index";
//特定的蓝牙设备的协议状态,用于拓展公共的蓝牙协议状态
//使用场景:
//在手机接收到蓝牙数据成功或失败后,该框架会生成一条消息,包含了对应的蓝牙协议状态值{protocolState}以及对应的{effectiveData}(effectiveData示例见 lb-example-bluetooth-protocol.js),
//在{setBLEListener}的{onReceiveData}回调函数中,对应参数{protocolState}和{value}(value就是effectiveData)
const ProtocolState = {
...CommonProtocolState,
RECEIVE_COLOR: 'receive_color',//获取到设备的颜色值
RECEIVE_BRIGHTNESS: 'receive_brightness',//获取到设备的亮度
RECEIVE_LIGHT_CLOSE: 'receive_close',//获取到设备灯光关闭事件
};
export {
ProtocolState, CommonConnectState as ConnectState
};
Geschäft | Entsprechender Ordner | Beispieldatei |
---|---|---|
Bluetooth-Verbindung | lb-ble-common-connection (Verarbeitung von Verbindungs-, Trennungs- und Wiederverbindungsereignissen) | abstract-bluetooth.js (am einfachsten, Aufruf der Plattform-API zum Verbinden, Trennen von Bluetooth usw.)base-bluetooth.js (zeichnet die Geräte-ID, den Kennwert, den Verbindungsstatus und andere Informationen des verbundenen Geräts auf, kümmert sich um das Senden von Bluetooth-Daten und die Bluetooth-Wiederverbindung)base-bluetooth-imp.js (erfasst Bluetooth-Verbindungsergebnisse, überwacht Bluetooth-Scans von umliegenden Geräten, Verbindungen und Adapterstatusereignissen und behandelt sie entsprechend) |
Aufbau des Bluetooth-Protokolls | lb-ble-common-protocol-body (Implementierung der Assemblierung des Protokoll-Transceiver-Formats) | i-protocol-receive-body.js i-protocol-send-body.js |
Senden und Empfangen des Bluetooth-Protokolls | lb-ble-common-protocol-operator (Agent, der das Senden und Empfangen von Daten übernimmt) | lb-bluetooth-protocol-operator.js |
Neuübertragung des Bluetooth-Protokolls | lb-ble-common-connection | lb-bluetooth-manager.js (siehe LBlueToothCommonManager für Details) |
Bluetooth-Status und Protokollstatus | lb-ble-common-state | lb-bluetooth-state-example.js , wodurch zusätzlich neue Zustände erweitert werden können |
Abonnements für Bluetooth-Verbindungs- und Protokollstatusereignisse | lb-ble-common-connection/base | base-bluetooth-imp.js |
Lassen Sie uns über die Verteilung der Bluetooth-Verbindung und den Protokollstatus sprechen.
Die Datei befindet sich unter lb-ble-common-connection/base/base-bluetooth.js
latestConnectState
-Objekt zugewiesen.setter
-Funktion set latestConnectState
._onConnectStateChanged
im setter
aus.onConnectStateChanged({connectState})
von getAppBLEManager.setBLEListener
empfangen. onBLECharacteristicValueChange
befindet sich in lb-ble-common-connection/abstract-bluetooth.js
receiveOperation
befindet sich in lb-ble-common-protocol-operator/lb-bluetooth-protocol-operator.js
In der Funktion onBLECharacteristicValueChange
fange ich nach dem Empfang der Daten die gültigen Daten gemäß receive-body.js
ab und verarbeite die gültigen Daten gemäß der Konfigurationsmethode von getReceiveAction
in lb-example-bluetooth-protocol.js
um den entsprechenden value, protocolState
zu erzeugen value, protocolState
. filter
wird generiert, wenn ein unbekanntes Protokoll empfangen wird.
onBLECharacteristicValueChange((res) => {
console.log('接收到消息', res);
if (!!valueChangeListener) {
const {value, protocolState, filter} = this.dealReceiveData({receiveBuffer: res.value});
!filter && valueChangeListener({protocolState, value});
}
});
Dieser Code sieht einfach aus, aber dahinter stecken viele Prozesse. Das Wichtigste ist diese Zeile const {value, protocolState, filter} = this.dealReceiveData({receiveBuffer: res.value});
;. Lassen Sie mich im Detail erklären, was diese Arbeitsrichtung bewirkt hat:
dealReceiveData
aus, um die Protokolldaten zu verarbeiten. dealReceiveData
werden hier letztendlich an die Funktion dealReceiveData
in lb-bluetooth-manager.js
übergeben, um die Daten zu verarbeiten.this.bluetoothProtocol.receive({receiveBuffer})
in dealReceiveData
aus, um gültige Daten und Protokollstatus zu generieren. Dieser receive
wird letztendlich von der Funktion receiveOperation
ausgeführt.receiveOperation
ausgeführt wird, verweist es auf das Konfigurationselement getReceiveAction
der Unterklasse von LBlueToothProtocolOperator
(die Unterklasse ist lb-example-bluetooth-protocol.js
).getReceiveAction
gibt schließlich das vereinbarte Objekt {protocolState,effectiveData}
gemäß der eigenen Implementierung des Entwicklers zurück. Nachdem das Objekt an receiveOperation
zurückgegeben wurde, wird es überprüft (der nicht in getReceiveAction
konfigurierte protocolState
wird als CommonProtocolState.UNKNOWN
verarbeitet) und das vereinbarte Objekt zurückgegeben an dealReceiveData
Lokale Variablen effectiveData, protocolState
in der Funktion.protocolState!==CommonProtocolState.UNKNOWN
wird als filter:true
markiert; andernfalls wird das vereinbarte Objekt an den lokalen value, protocolState
in der Funktion onBLECharacteristicValueChange
zurückgegeben.Das ist alles, was diese Codezeile tut.
Das vereinbarte Objekt wird als Parameter an valueChangeListener({protocolState, value})
übergeben und der Rückruf wird ausgeführt. Danach kann das Frontend die abonnierten Ereignisse empfangen, d. h. der Protokolltyp und das value
werden in onReceiveData({protocolState, value})
von getAppBLEManager.setBLEListener
empfangen.
Dokumentieren
ChangeLog
Qualitätssicherung
LIZENZ
Für den technischen Austausch treten Sie bitte der QQ-Gruppe bei: 821711186