04 蓝牙模块 - MiEcosystem/ios-rn-sdk GitHub Wiki
米家扩展程序主要由三个基础模块组成分别是支持小米蓝牙协议的MHBluetooth模块、MHXiaomiBLE模块和用于普通蓝牙设备的MHBluetoothLE模块。MHBluetooth封装了最基础的连接、断开、发现服务、读写、监听广播等功能,使用方式类似于 CoreBluetooth。MHXiaomiBLE则是提供了若干小米蓝牙协议功能性方法,例如加密、获取bindkey等。
扩展程序通过 MHBluetooth 模块与支持小米蓝牙协议的设备交互。此模块中封装了与米家对接的蓝牙设备连接、断开、发现服务、读写、监听广播等功能。使用方式类似于 CoreBluetooth。
如果该模块中的 API 不能全部满足业务需求,可使用 MHBluetoothLE
加 MHXiaomiBLE
模块来实现。
注意扩展程序需要正确处理蓝牙的连接与断开。用户退出插件时,必须断开连接。
// 模块初始化
var MHBluetooth = require('NativeModules').MHBluetooth;
我们提供了一个蓝牙示例插件,见 com.xiaomi.bledemo.ios 目录
无
苹果的 CoreBluetooth 框架中,调用 CBCentralManager 与 CBPeripheral 的方法,分别通过 CBCentralManagerDelegate 与 CBPeripheralDelegate 的回调方法返回结果。MHBluetooth 采用与此类似的方式,由插件注册监听事件通知来处理相应的回调。
MHBluetooth 只会接收当前插件控制的设备的事件。
蓝牙事件的规则如下:
-
CBCentralManagerDelegate 以及 CBPeripheralDelegate 中的大部分回调方法(简称 CB 回调 )在 MHBluetooth 中都有对应的通知事件(简称 M 事件 )。目前有部分不常用的方法没有对应的通知事件
-
M 事件 与其对应的 CB 回调 的含义、功能以及调用时机完全相同。
-
单参数的 CB 回调,M 事件 名称与 CB 回调 名相同(字母、大小写均相同)。如: CB 回调 :
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
对应的 M 事件 为:
MHBluetooth.centralManagerDidUpdateState
-
多参数的 CB 回调,M 事件名称为每段CB 回调名以下划线"_"连接。如: CB 回调 :
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
对应的 M 事件 为:
MHBluetooth.centralManager_didDisconnectPeripheral_error
-
CB 回调 的参数,会通过 M 事件 携带在通知中广播给插件,但 centralManager 和 peripheral 参数会被过滤掉。
// 监听事件示例代码
var {DeviceEventEmitter} = require('react-native');
var subscription = DeviceEventEmitter.addListener(MHBluetooth.peripheral_didDiscoverServices,(notification) => {
console.log(JSON.stringify(notification));
MHBluetooth.serviceUUIDsWithCallback((uuids) => {
console.log(uuids);
});
});
注意 与其他普通事件一样,监听的事件通知,需要在 componentWillUnmount 方法中取消监听。
// 取消监听事件示例代码
componentWillUnmount() {
if (subscription)
{
subscription.remove();
}
}
具体可以参见 SDK 中附带的蓝牙示例插件 com.xiaomi.bledemo.ios
蓝牙开关状态改变
设备已连接
设备连接失败
设备断开连接
设备服务发现完毕
服务的特征发现完毕
服务特征值发生更新(被 read 之后,或收到设备 notify 通知)
服务特征值写入完毕
服务特征值 notify 状态发生改变
读到新的 RSSI
RSSI 更新
发现当前设备peripheral的services。
var {DeviceEventEmitter} = require('react-native');
var subscription = DeviceEventEmitter.addListener(MHBluetooth.peripheral_didDiscoverServices,(notification) => {
console.log(JSON.stringify(notification));
MHBluetooth.serviceUUIDsWithCallback((uuids) => {
console.log(uuids);
});
});
MHBluetooth.discoverServices();
发现当前设备peripheral的指定service的characteristics
serviceUUID
服务的 UUID 字符串
读取当前设备peripheral的指定characteristic的值(base64编码)
characteristicUUID
指定characteristic的UUID字符串serviceUUID
指定service的UUID字符串callback
回调方法 (bool isSuccess, [characteristicUUID, serviceUUID])注意 该方法的 callback 并不能返回数据,只是返回读取是否成功,数据的返回与 CoreBluetooth 一样,会通过对应的回调方法。
var {DeviceEventEmitter} = require('react-native'); // 订阅特征值更新通知 var subscription = DeviceEventEmitter.addListener(MHBluetooth.peripheral_didUpdateValueForCharacteristic_error,(notification) => { console.log(JSON.stringify(notification)); }); // 读取特征值 MHBluetooth.readBase64DataWithCallback("0001", "fe95", (isSuccess, loopbackParams) => { // });
向当前设备peripheral的指定characteristic写入值(base64编码)
data
写入的数据,用base64编码,写入时会自动解码characteristicUUID
指定characteristic的UUID字符串serviceUUID
指定service的UUID字符串type
写入方式(0=需要response, 1=不需要response)callback
回调方法 (bool isSuccess, [data, characteristicUUID, serviceUUID, type])注意 该方法的 callback 并不能返回设备侧是否写入成功,只是返回APP侧写入命令执行是否成功,与 CoreBluetooth 一样,会通过对应的回调方法返回写入成功( type=0 的情况下)。
向当前设备peripheral的指定characteristic写入值(16进制字符串格式)
data
写入的数据,用16进制字符串格式,写入时会自动解码characteristicUUID
指定characteristic的UUID字符串serviceUUID
指定service的UUID字符串type
写入方式(0=需要response, 1=不需要response)callback
回调方法 (bool isSuccess, [data, characteristicUUID, serviceUUID, type])注意 该方法的 callback 并不能返回设备侧是否写入成功,只是返回APP侧写入命令执行是否成功,与 CoreBluetooth 一样,会通过对应的回调方法返回写入成功( type=0 的情况下)。
设置当前设备peripheral的指定characteristic的通知状态
needNotify
是否打开通知characteristicUUID
指定characteristic的UUID字符串serviceUUID
指定service的UUID字符串callback
回调方法 (bool isSuccess, [needNotify, characteristicUUID, serviceUUID])
当前设备所有已发现的service的UUIDs
callback
回调方法 (Array serviceUUIDs)
当前设备所有发现了的指定service的characteristic的UUIDs
serviceUUID
指定service的UUID字符串callback
回调方法 (Array characteristicUUIDs, [serviceUUIDs])
开始监听当前设备的广播
可通过监听MHBluetooth.receivedBroadcastEventName事件收到广播中的数据
开始监听当前设备的广播(重复的peripheral只回调一次)
可通过监听MHBluetooth.receivedBroadcastEventName事件收到广播中的数据
停止监听当前设备的广播
重新连接设备
callback
回调方法 (bool isSuccess)
断开设备
非小米协议的蓝牙设备扫描发现 callback 回调方法**(error.code)** 200为成功发现,404为未发现,其他为错误码
seconds 超时时间秒数 callback 回调方法**(error.code)** 200为成功发现,404为未发现,其他为错误码,错误码为3时需要重新注册
小米协议的蓝牙设备注册 callback 回调方法**(error.code)** 200为成功发现,404为未发现,其他为错误码
获取自定义数据 callback 回调方法**(base64ManufaxtureData)** 自定义数据的base64编码值
设置设备列表离线状态(蓝牙未连接)副标题 desc 字符串
设置设备列表在线状态(蓝牙连接)副标题 desc 字符串
设置设备列表默认副标题 desc 字符串
获取蓝牙状态
MHBluetooth.getBluetoothStateCallback((state)=>{
//CBManagerStateUnknown = 0,
//CBManagerStateResetting,
//CBManagerStateUnsupported,
//CBManagerStateUnauthorized,
//CBManagerStatePoweredOff,
//CBManagerStatePoweredOn,
});
获取蓝牙peripheral信息
MHBluetooth.getPeripheralInfo((success,peripheral)=>{
if(success){
console.warn(peripheral);
}
});
获取蓝牙peripheral rssi信息
peripheral_didReadRSSI_error 通过此事件监听rssi值回调
peripheralDidUpdateRSSI_error 通过此事件监听rssi error信息
//添加监听
...
MHBluetooth.readRSSI();
在米家扩展程序快联开发过程中有部分蓝牙模块使用的是小米蓝牙,由于小米蓝牙的特殊性,我们对使用小米蓝牙模块的设备提供了一个特殊的模块MHXiaomiBLE
来更快捷的绑定蓝牙设备到米家客户端。
只支持使用小米蓝牙模块的设备。并注意正确处理蓝牙的连接与断开。用户退出扩展程序时,必须断开连接。
// 模块初始化
var MHXiaomiBLE = require('NativeModules').MHXiaomiBLE;
####didFoundXiaoMiBLEDevice 发现小米某model的蓝牙设备通知
MHXiaomiBLE.didFoundXiaoMiBLEDevice
描述:获取默认的蓝牙设备属性
参数:
-
callback(error, device)
error表示是否有错误,device表示默认设备
例子:
MHXiaomiBLE.getDefaultDevice((error, device) => {
if(error){
MHPluginSDK.showFailedTips('获取失败:'+error.message);
}
});
描述:搜索某model的小米蓝牙设备
参数:
-
model
设备的model -
callback(error, timeout, devices)
error 是否有错误,timeout搜索时间,devices搜索结果
例子:
MHXiaomiBLE.scanXiaoMiBLE('xiaomo.rocket.v1',4, (error, device) => {
if(error){
MHPluginSDK.showFailedTips('搜索失败:'+error.message);
}
});
搜索结果在设定时间之后调用callback把结果返回,每当MHXiaomiBLE模块搜索到一个符合条件的设备的时候会发生通知MHXiaomiBLE.didFoundXiaoMiBLEDevice, 可以监听该通知以实时获取搜索到的设备。
描述:把设备注册到米家客户端(一般是第一次连接的设备调用此函数,包含绑定设备逻辑)
参数:
-
did
需要注册到米家客户端的设备ID -
mac
设备的mac地址 -
timeout
注册超时时间,如果在超时时间内未完成注册则取消注册 -
callback(error, info)
当注册结束后调用此回调 error表示是否注册成功,info表示注册的设备信息
例子:
MHXiaomiBLE.registerXiaoMiBLE('xdffe98sd9', '09:09:09:09:09', 10, (error, info) => {
if(error){
MHPluginSDK.showFailedTips('注册失败:'+error.message);
}
});
描述:米家客户端打开并登录设备(一般是打开已连接或者曾经连接过设备调用此函数,包含重新绑定设备逻辑)
参数:
-
did
需要登录的设备ID -
mac
设备的mac地址 -
timeout
登录超时时间,如果在超时时间内未完成登录则取消登录 -
callback(error, info)
当登录结束后调用此回调 error表示是否登录成功,info表示登录的设备信息
例子:
MHXiaomiBLE.loginXiaoMiBLE('xdffe98sd9', '09:09:09:09:09', 10, (error, info) => {
if(error){
MHPluginSDK.showFailedTips('登录失败:'+error.message);
}
});
注意,若登录失败,请查看 error
中的 code
错误码,错误码说明如下:
0
— 设备无法连接
1
— 设备登录时蓝牙连接断开
2
— 蓝牙读写失败
3
— token 发生变化导致的失败,需要重新注册获取新的 token
4
— 成功,一般不会出现在 error
中
5
— 未知错误
6
— 设备被重置,有安全风险,请提醒用户使用 APP 解绑设备,并重新添加
7
— 未获取到有效的电子钥匙
8
— 设备数字证书不可信
描述:把设备绑定到米家客户端
参数:
-
did
需要绑定到米家客户端的设备ID -
mac
设备的mac地址 -
callback(error, info)
当绑定结束后调用此回调 error表示是否绑定成功,info表示绑定的设备信息
例子:
MHXiaomiBLE.bindXiaoMiBLE('xdffe98sd9', '09:09:09:09:09', (error, info) => {
if(error){
MHPluginSDK.showFailedTips('注册失败:'+error.message);
}
});
描述:设备断开连接
参数:
-
did
设备ID -
mac
设备的mac地址 -
callback(error, info)
断开结束后调用此回调 error表示是否绑定成功,info表示绑定的设备信息
例子:
MHXiaomiBLE.disconnectXiaoMiBLE('xdffe98sd9', '09:09:09:09:09', (error, info) => {
});
描述:支持小米加密芯片的蓝牙设备,使用此方法将明文加密为密文后,可发送给设备
参数:
-
message
待加密的明文 -
callback(error,encrypted)
加密回调,error 表示是否成功,encrypted 表示加密后的数据例子:
MHXiaomiBLE.encryptMessageXiaoMiBLE(msg,(error,encrypted)=>{ if (error) { // 出错 return; } //console.log(encrypted.string); });
描述:支持小米加密芯片的蓝牙设备,使用此方法,可将从设备接收的密文解密
参数:
-
encrypted
待解密密文 -
callback(error,message)
解密回调,error 表示是否成功,message 表示解密后的数据例子:
MHXiaomiBLE.decryptMessageXiaoMiBLE(message,(error,decrypted)=>{ if (error) { //出错 return; } //console.log("解密消息内容为 " + JSON.stringify(decrypted)); });
描述:小米安全芯片门锁便捷开关
参数:
-
cmd
操作命令,可传入0
,1
,2
三个 int 值,分别代表 开锁,上锁,反锁 -
timeoutInterval
超时时间,类型为 float,单位为秒,若对应时间过去后仍没有回到设备的开关锁回复,则 callback 返回超时 error -
callback(error,message)
回调,error 表示是否成功例子:
MHXiaomiBLE.toggleLockXiaoMiBLE(1,2.0,(error, message)=>{ if (error) { //出错 return; } //console.log("上锁成功"); });
描述:支持小米加密芯片的蓝牙设备,使用此方法,可获得设备注册后,生成的 token 的 MD5 值
-
callback(error,message)
回调,error 表示错误,message 表示获取的数据
描述:支持小米加密芯片的蓝牙设备,在被分享的设备中,调用此方法,可判断分享的电子钥匙是否过期
-
callback(error,message)
回调,error 表示错误,message 表示获取的数据例子:
MHXiaomiBLE.isShareSecureKeyValid((error,message)=>{ if(!error){ //根据 message 中的 ’valid‘ 字段判断,1 -- 有效;0 -- 无效(已经过期) } })
描述:支持小米蓝牙协议的,且已经连接的设备可通过此方法获取bindKey
-
callback(isSuccess, message)
回调,isSuccess表示是否成功, message在成功的情况下表示bindkey, 在失败的情况下表示error。例子:
MHXiaomiBLE.getBindKey((isSuccess,message)=>{ if(isSuccess){ // bindkey } else { // error } })
描述:支持米家安全芯片的设备,通过此方法获取一次性密码组
-
interval
,时间间隔,单位为秒,类型为 number,传入 1 到 60 的整数 -
digits
,密码位数,类型为 number,传入 6 到 8 的整数 -
callback
回调,密码组或者错误通过此返回
示例:
MHXiaomiBLE.oneTimePassword(30, 8, (error,passwds)=>{
if(!error){
//parse passwds array
}
});
扩展程序通过 MHBluetoothLE 模块与蓝牙设备交互。此模块中封装了普通蓝牙设备的连接、断开、发现服务、读写、监听广播等功能。使用方式类似于 iOS开发中的CoreBluetooth.framework。
注意扩展程序需要正确处理蓝牙的连接与断开。用户退出插件时,必须断开连接。
// 模块初始化
var MHBluetoothLE = require('NativeModules').MHBluetoothLE;
我们提供了一个蓝牙示例程序,见 com.xiaomi.corebledemo.ios 目录
MHBluetoothLE
模块所有的消息类型 Object
central mananger 状态发生改变(蓝牙关闭,打开等)
设备断开连接
设备连接成功
设备连接失败
发现设备
设备名称改变
设备服务修改
设备RSSI值更改(<=iOS8)
设备RSSI值读取和改变(>iOS8)
发现设备支持的所有服务
发现某服务下的服务
发现某服务下的特征
某服务特征内容发生改变(读取或者通知)
向某服务特征写入数据完成
某通知类型服务特征改变通知状态
发现某服务特征描述
某服务特征描述内容发生改变(读取)
向某服务特征描述写入数据完成
var events = MHBluetoothLE.event;
MHBluetoothLE
模块扫描设备的选项key
类型: Object
- scanOption.allowDuplicatesKey 设置一个Boolean值表示扫描时是否需要重复过滤
- scanOption.solicitedServiceUUIDsKey 指定此扫描选项将导致管理器也扫描寻求数组中包含的任何服务的外设。
MHBluetoothLE
模块初始化选项(目前暂时不支持)
MHBluetoothLE
模块连接设备的选项key Object
- connectOption.notifiOnConnectKey 设置一个Boolean值表示在应用suspended后设备连接成功是否显示系统弹窗
- connectOption.notifyOnDisconnectionKey 设置一个Boolean值表示在应用suspended后设备断开连接是否显示系统弹窗
- connectOption.notifyOnNotificationKey 设置一个Boolean值表示在应用suspended后接收到设备通知是否显示系统弹窗
苹果的 CoreBluetooth 框架中,调用 CBCentralManager 与 CBPeripheral 的方法,分别通过 CBCentralManagerDelegate 与 CBPeripheralDelegate 的回调方法返回结果。MHBluetoothLE 采用与此类似的方式,由插件注册监听事件通知来处理相应的回调。另外MHBluetoothLE支持回调绑定,可在调用接口时传递callback方法,MHBluetoothLE会根据本次调用来回调callback方法返回本次结果(回调绑定后仅调用一次)
MHBluetooth 接收MHBluetooth模块扫描到的设备的事件。
蓝牙事件的规则如下:
-
CBCentralManagerDelegate 以及 CBPeripheralDelegate 中的大部分回调方法(简称 CB 回调 )在 MHBluetoothLE 中都有对应的通知事件(简称 M 事件 )。
-
M 事件 与其对应的 CB 回调 的含义、功能以及调用时机完全相同。
-
单参数的 CB 回调,M 事件 名称与 CB 回调 名相同(字母、大小写均相同)。如: CB 回调 :
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
对应的 M 事件 为:
MHBluetoothLE.event.centralManagerDidUpdateState
-
多参数的 CB 回调,M 事件名称为每段CB 回调名以下划线"_"连接。如: CB 回调 :
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
对应的 M 事件 为:
MHBluetoothLE.event.centralManager_didDisconnectPeripheral_error
-
CB 回调 的参数,会通过 M 事件 携带在通知中广播给插件,但 centralManager 和 peripheral 参数会被过滤掉。
// 监听事件示例代码
var {DeviceEventEmitter} = require('react-native');
var subscription = DeviceEventEmitter.addListener(MHBluetoothLE.event.peripheral_didDiscoverServices,(notification) => {
console.log(JSON.stringify(notification));
var error = notification[0];
if(error) {
MHPluginSDK.showFialedTips(error.message);
return;
}
var peripheral = notification[1];
var services = notification[2];
});
注意: 与其他普通事件一样,监听的事件通知,需要在 componentWillUnmount 方法中取消监听。
// 取消监听事件示例代码
componentWillUnmount() {
if (subscription)
{
subscription.remove();
}
}
具体可以参见 SDK 中附带的蓝牙示例插件 com.xiaomi.corebledemo.ios
无
大部分接口回调的第一个参数常为一个错误对象,该对象格式如下:
{
code:1, //表示发生错误的层级 1表示设备错误,2表示服务错误,3表示特征错误,4表示描述错误,5表示其他错误
message:'xx,xx', //错误的描述信息
peripheral:'FFF0',//发生错误的设备identifier
service:'FFF1', //发生错误的服务UUID
characteristic:'FFF2', //发生错误的特征UUID
domain:'characteristic' //发生错误的域,参加code
}
MHBluetoothLE 的API导出了大部分CBCentralManager
和CBPeripheral
的方法。有OC开发经验的可参看CoreBluetooth.framework
的文档
描述:扫描周围的蓝牙设备
参数:
-
service
你想要扫描到包含次服务的设备 Array(String); -
options
设置的扫描选项 -
callback
扫描错误回调,当调取扫描失败的时候会调用此回调
例子:
MHPluginSDK.showLoadingTips('开始扫描附近的小米蓝牙开发板');
var options = {};
options[MHBluetoothLE.scanOption.allowDuplicatesKey] = true,
options[MHBluetoothLE.scanOption.solicitedServiceUUIDsKey] = [serviceUUID];
MHBluetoothLE.startScan([ServiceUUID], options, (error) => {
MHPluginSDK.dismissTips();
if(error){
MHPluginSDk.showFailedTips(error.message);
}
});
描述:停止设备扫描
参数:
-
callback
停止失败时回调用此方法
例子:
MHBluetoothLE.stopScan(() => {});
描述: 蓝牙是否可用
参数:
-
callback(isEnable)
同过callback来返回结果,callback参数为boolean值,ture表示可用,false表示不可用
例子:
MHBluetoothLE.isEnabled((isEnable) => {
if(isEnable){
//do your work
}
});
描述:检索所有包含identifiers中指定UUID的设备
参数:
-
identifiers
需要检索的设备的UUID Array(String) -
callback(devices)
结果返回回调 返回检索到的所有设备 并与devices方式返回{'some_peripheral_identifier_A':{ identifier: 'xxxxx', services: [], name: 'xxx', state: 'connected', rssi: -50 }, 'some_peripheral_identifier_B':{ identifier: 'xxxxx', services: [], name: 'xxx', state: 'connected', rssi: -50 }, }
描述:检索所有包含identifiers中指定UUID的已连接的设备
参数:
-
identifiers
需要检索的设备的UUID Array(String) -
callback(error, devices)
结果返回回调 返回检索到的所有设备 并与devices方式返回 格式如下:{'some_peripheral_identifier_A':{ identifier: 'xxxxx', services: [], name: 'xxx', state: 'connected', rssi: -50 }, 'some_peripheral_identifier_B':{ identifier: 'xxxxx', services: [], name: 'xxx', state: 'connected', rssi: -50 }, }
描述:获取控制页默认设备信息(可能没有默认设备)
参数:
-
callback(error, device)
结果返回回调 结果device如下格式:{ model:'', //设备的model did: '', //设备的device id name: '', //设备的名称 token: '', //设备的token broadcastNotificationName: '', // 设备的广播名称 extra: {}, // 设备的额外信息 peripheral: {}, // 设备蓝牙信息 }
描述:通过did连接原生页传递到插件页的设备(能够连接的设备是通过getDeviceList()方法返回的设备)
参数:
-
did
设备的device id -
callback(error peripheral)
结果回调
例子:
MHBluetoothLE.connectDevice(did, (error, peripheral) => {
});
描述:获取原生蓝牙扫描页面传递到本地插件页面的设备列表
参数:
-
callback(error, devices)
结果回调
描述: 连接插件扫描到的设备
参数:
-
identifier
设备的identitier -
options
连接配置选项 设置key 参见 常量connectOption
-
callback(error, peripheral)
结果回调
例子:
MHPluginSDK.showLoadingTips('设备连接中..');
MHBluetoothLE.connect(peripheral.identifier, {}, (error, result) => {
MHPluginSDK.dismissTips();
if (error) {
MHPluginSDK.showFailTips('设备连接失败');
return;
}
this._connectSuccess(result);
});
描述: 断开设备连接
参数:
-
identifier
设备的identifier -
callback(error, peripheral)
结果回调
例子:
MHBluetoothLE.disconnect(this.props.peripheral.identifier, () => {});
描述:扫描到的所有设备列表
参数:
-
callback(error, peripherals)
结果回调 peripherals 为蓝牙设备数组
描述: 设备是否已经连接
参数:
-
identifier
需要查询的蓝牙设备identifier -
callback(error, isConnected)
结果回调 isConnected为true时表示已连接,false是断开连接
描述:读取设备的RSSI
参数:
-
identifier
需要查询的蓝牙设备identifier -
callback(error, peripheral, rssi)
error表示是否有错误 peripheral是查询的蓝牙设备信息,rssi是该蓝牙设备的信号强度
例子:
MHBluetoothLE.readRSSI(peripheral.identifier, (error, peripheral, rssi) => {
//alert(JSON.stringify(peripheral));
});
描述:读取设备的名称
参数:
-
identifier
需要查询的蓝牙设备identifier -
callback(error, name)
error表示是否有错误, name是该蓝牙设备的名称
描述:读取设备的详细信息
参数:
-
identifier
需要查询的蓝牙设备identifier -
callback(error, peripheral)
error表示是否有错误, peripheral是该蓝牙设备的详细信息,格式如下:{ identifier: 'FFF0', //蓝牙设备的identifier name: '小米蓝牙开发板', //蓝牙设备名称 rssi: -50, //蓝牙设备的RSSI强度 state: 'connected', //蓝牙设备的连接状态(disconnected, connecting, connected, disconnecting, unknown) services: {}, //蓝牙设备支持的服务 以服务的uuid作为key,服务信息详情作为value }
- connected 已连接
- connecting 正在连接
- disconnected 已断开
- disconnecting 正在断开连接
- unknown 未知
描述:读取某设备的某项服务的详细信息
参数:
-
serviceUUID
所查询的服务的UUID -
identifier
需要查询的蓝牙设备identifier -
callback(error, service)
error表示是否有错误, service是该蓝牙设备某服务的详细信息,格式如下:{ peripheral: 'FFF0', //该服务所属蓝牙设备的identifier uuid: 'FFEF', //服务的UUID isPrimary: true, //服务是否是主服务 includeServices: {}, //服务支持的包含服务 以服务的uuid作为key,服务信息详情作为value characteristics: {}, //服务支持的特征 以特征的uuid作为key,特征信息详情作为value }
描述: 读取某设备某项服务的某特征的详细信息
参数:
-
characteristicUUID
查询的特征的UUID -
serviceUUID
查询的特征所属服务的UUID -
identifier
需要查询的蓝牙设备identifier -
callback(error, characteristic)
error表示是否有错误, characteristic是该蓝牙设备某服务的某特征的详细信息,格式如下:{ peripheral: 'FFF0', //该特征所属服务服务所属蓝牙设备的identifier service: 'FFF1', //该特征所属服务的UUID uuid: 'FFEF', //特征的UUID isNotifying: true, //特征是否是开启通知 isBroadcasted: true, //特征是否是开启广播 properties: 'broadcast', //特征类型 descriptors: {}, //服务支持的描述 以描述的uuid作为key,描述信息详情作为value }
- bradcast 广播数据
- read 读数据
- writeWithoutResponse 无响应写数据
- write 有响应写数据
- notify 通知
- indicate 表现
- authenticatedSignedWrites
- extendedProperties
- notifyEncryptionRequired
- indicateEncryptionRequired
- unknown
描述: 读取某设备某项服务的某特征的某描述的详细信息
参数:
-
descriptorUUID
查询的描述的UUID -
characteristicUUID
查询的描述所属特征的UUID -
serviceUUID
查询的特征所属服务的UUID -
identifier
需要查询的蓝牙设备identifier -
callback(error, descriptor)
error表示是否有错误, descriptor是该蓝牙设备某服务的某特征的某描述的详细信息,格式如下:{ peripheral: 'FFF0', //该服务所属蓝牙设备的identifier service: 'FFF1', //该描述所属服务的uuid characteristic: 'FFF2',//该描述所诉特征的UUID uuid: 'FFEF', //服务的UUID value: Object/String, //描述的其他信息 }
描述:发现当前设备peripheral的services,
参数:
-
identifier
需要查询的蓝牙设备identifier -
services
需要发现的service的UUID数组 当services=[]时表示查询此设备支持的所有服务 -
callback(error, peripheral, services)
error表示是否有错误,peripheral表示设备的信息,services表发现到的服务
例子:
//搜索设备的服务
MHBluetoothLE.discoverServices(this.state.device.peripheral.identifier, [UUID_SERVICE], (error, peripheral, services) => {
if (!error && services[UUID_SERVICE]) {
this._initCharacteristicStatus(services[UUID_SERVICE]);
}else {
MHPluginSDK.showFailTips('未能找到匹配的操作:'+error.message);
}
});
描述:发现当前设备peripheral的某service种的includeServices,
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
services
需要发现的service的UUID数组 当services=[]时表示查询此设备支持的所有服务 -
callback(error, service, includeServices)
error表示是否有错误,service表示设备的服务信息,includeServices表示发现到的服务
例子:
//搜索设备的服务
MHBluetoothLE.discoverIncludeServices(this.state.device.peripheral.identifier, service [UUID_SERVICE], (error, peripheral, inscludeServices) => {
if (!error && inscludeServices[UUID_SERVICE]) {
this._initCharacteristicStatus(inscludeServices[UUID_SERVICE]);
}else {
MHPluginSDK.showFailTips('未能找到匹配的操作:'+error.message);
}
});
描述:发现当前设备的某服务的特征
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
charas
期望发现的characteristic的UUID数组 -
callback(error, service, characteristics)
error表示是否有错误,service表示设备的服务信息,characteristics表示发现到的特征
例子:
MHBluetoothLE.discoverCharacteristics(this.state.device.peripheral.identifier, serivceUUID, characteristicUUIDs, (error, serivce, characteristics) => {
if (!error) {
//通知是否被打开
//do your task
}
});
描述:发现当前设备的某服务的某特征的描述
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
callback(error, characteristic, descriptors)
error表示是否有错误,characteristic表示特征信息,descriptors表示发现到的特征描述
例子:
MHBluetoothLE.discoverDescriptors(characteristic.peripheral, characteristic.service, characteristic.uuid, (error, peri, descriptrors) => {
if (error) {
MHPluginSDK.showFailTips('查找失败');
}else {
MHPluginSDK.showFinishTips('搜索完成');
this.setState({dataSource: this.state.dataSource.cloneWithRows(
this._genRows(descriptrors)
)});
}
});
描述:读取某设备的某服务的某特征值
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
callback(error, characteristic, msgData)
error表示是否有错误,characteristic表示特征信息,msgData 读取到的特征值,格式为16进制字符串 例如'807f9042'。
例子:
MHBluetoothLE.readValue(service.peripheral, service.uuid, CharacteristicUUID_READ_NORDIC, (error, chara, msgData) => {
if (error) {
MHPluginSDK.showFilTips('获取数据失败');
return;
}
//处理数据
this._handleMsgForNineBot(msgData);
});
描述:向某设备的某服务的某特征写入数据
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
msg
发生到设备端的16进制字符串 例如:'FF00FF00' -
callback(error)
error表示是否有错误
例子:
MHBluetoothLE.writeWithoutResponse(service.peripheral, service.uuid, CharacteristicUUID_READ_NORDIC, 'FF00FF00', (error) => {
if (error) {
MHPluginSDK.showFilTips('数据写入失败');
return;
}
});
描述:向某设备的某服务的某特征写入数据
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
msg
发生到设备端的16进制字符串 例如:'FF00FF00' -
callback(error, characteristic)
error表示是否有错误 characteristic写入成功的特征
例子:
MHBluetoothLE.writeWithoutResponse(service.peripheral, service.uuid, CharacteristicUUID_READ_NORDIC, 'FF00FF00', (error, characteristc) => {
if (error) {
MHPluginSDK.showFilTips('数据写入失败');
return;
}
});
描述:打开某特征的通知功能
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要打开通知的characteristic的UUID -
callback(error, characteristic, isNotifying)
error表示是否有错误 characteristic写入成功的特征
例子:
MHBluetoothLE.enableNotify(characteristic.peripheral, characteristic.service, characteristic.uuid, (error, characteristic, isNotifying) => {
if(error){
MHPluginSDK.showFailTips('打开失败');
this._notifySwitch.setSwichByProps(!isOn);
}
this.state.isNotifying = isOn;
});
描述:关闭某特征的通知功能
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要打开通知的characteristic的UUID -
callback(error, characteristic, isNotifying)
error表示是否有错误 characteristic写入成功的特征
例子:
MHBluetoothLE.disableNotify(characteristic.peripheral, characteristic.service, characteristic.uuid, (error, characteristic, isNotifying) => {
if(error){
MHPluginSDK.showFailTips('关闭失败');
this._notifySwitch.setSwichByProps(!isOn);
}
this.state.isNotifying = isOn;
});
描述:读取某设备的某服务的某特征值
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
descriptorUUID
读取数据的descriptor的UUID -
callback(error, descriptor, msgData)
error表示是否有错误,descriptor表示描述的信息,msgData 读取到的描述值(类型不确定)。
例子:
MHBluetoothLE.readDescriptorValue(descriptor.peripheral, descriptor.service, descriptor.characteristic, descriptor.uuid, (error, result, body) => {
if (!error) {
alert(JSON.stringify(body));
}else {
alert('error:'+error.message+JSON.stringify(result));
}
});
描述:读取某设备的某服务的某特征值
参数:
-
identifier
需要查询的蓝牙设备identifier -
serviceUUID
需要查询的service的UUID -
characteristic
需要查询的characteristic的UUID -
descriptorUUID
读取数据的descriptor的UUID -
body
写入到描述的数据(常用类型) -
callback(error, descriptor, msgData)
error表示是否有错误,descriptor表示描述的信息
例子:
MHBluetoothLE.writeDescriptorValue(descriptor.peripheral, descriptor.service, descriptor.characteristic, descriptor.uuid, '9f085a', (error, result) => {
if (error) {
alert(JSON.stringify(error));
}
});
API中大部分接口的最后一个参数是callback,此callback来回传本次操作的结果,此callback仅对本次操作有效,所以对于有些设备分多次返回数据的情况则callback方式并不适用,建议使用监听消息方式来获取多次获取操作结果。例如readValue()
,有些设备的数据过大,根据CoreBluetooth.framework文档,设备可能会分多次调用peripheral:didUpdateValueForCharacteristic:error代理, MHBluetoothLE模块的callback仅能获取第一次代理调用返回的数据,但是如果监听MHBluetoothLE.event.peripheral_didUpdateValueForCharacteristic_error事件就可以分多次获取全部数据。
callback回调的参数一般是(error,forWho, result)三参数形式返回,error表示是否有错误,forWho表示操作的是哪个层级的对象(peripheral, service, characteristic,descriptor),result是方法调用的结果
event消息返回一个数组对象的参数,数组内容格式:[error, forWho, result],error表示是否有错误,forWho表示操作的是哪个层级的对象(peripheral, service, characteristic,descriptor),result是方法调用的结果
MHBluetoothLE模块中JavaScript to Objective-c的数据的传递都是以16进制字符串的方式进行的,例如向设备端写入一个字符串'1111'
,那么需要把字符串'1111'
转换成16进制字符串'30303030'
;设备端向外发生数据时也会被MHBluetoothLE模块转换成16进制字符串的形式,例如设备端发送数据是数字123
, 那么MHBluetoothLE就会转换为'7B'
。
在com.xiaomi.corebledemo.ios/Main/XiaoMiBLEMainPage.js示例中提供了两个方法:
- _hexStrToByteArr(hexStr); //16进制字符串转换为10进制数数组
- _byteArrToHexStr(byteArr); //10进制数组转换为16进制字符串(10进制数接受范围是0~255, 包含0和255)
MHBluetoothLE模块是基于CoreBluetooth.framework框架开发,CoreBluetooth.framework部分接口存在调用后无响应(也就是超时),所以使用MHBluetoothLE时需要自己控制接口调用的超时处理,比如扫描设备,当没有扫描到设备事MHBluetoothLE并不会调用回调,也没有事件进行通知,所以需要调用者自行处理,例如如下代码:
MHPluginSDK.showLoadingTips('开始扫描附近的小米蓝牙开发板');
MHBluetoothLE.startScan([ServiceUUID], {}, (error) => {
MHPluginSDK.dismissTips();
});
//设置20秒的超时处理
setTimeout(() => {
if (this._isEmptyObject(discoverPeripherals)) {
MHPluginSDK.showFailTips('未发现附近的小米蓝牙开发板');
MHBluetoothLE.stopScan(() => {});
this.props.navigator.pop();
}else {
MHPluginSDK.dismissTips();
}
}, 20000);
我们在config.plist
配置项中新增了一个key:bleScanIsNeedDelegate
来配置自定义蓝牙设备插件快联是否需要被代理扫描蓝牙设备,如果配置true则表示需要,如果配置false则表示不需要代理扫描,此时需要插件快联页自己实现蓝牙设备扫描的逻辑。配置示例如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>pluginStructureVersion</key>
<integer>1</integer>
<key>deviceStatusRefreshInterval</key>
<integer>6</integer>
<key>bleScanIsNeedDelegate</key>
<true/>
</dict>
</plist>
更多代码示例请看com.xiaomi.corebledemo.ios
-
下载合作开发的sdk,用于调试,具体下载方式找米家开发人员。
-
找米家工作人员配置此设备model对应的快连方式(插件内快连)
-
实现相关类
-
MHDeviceBluetooth的子类
- 实现load方法注册设备model
- 给出设置控制类的类型
+ (void)load{ // 注册设备model,开发不支持小米蓝牙协议的普通蓝牙设备,请打开 [MHDevListManager registerDeviceModelId:XMBand2Model className:NSStringFromClass([self class]) isRegisterBase:YES]; } + (Class)iOTDeviceClass{ return [XMBand2BtDevice class]; }
-
MHBtDevice
- 传入广播参数,判断是否是本类设备广播 不要误判,会把别人的广播识别成自己的设备
- 传入广播参数,返回设备did值,did保证每个设备唯一且不变,通过uuid似乎可以,或者自己去实现
- 传入广播参数,返回设备类model,返回本设备model就行
+ (BOOL)isDeviceHit:(MHBluetoothBroadcastPackage *)broadcast{ NSDictionary *dic = broadcast.advertisementData; if ([[dic objectForKey:@"kCBAdvDataLocalName"] isEqualToString:@"MI Band 2"]) { return YES; } return NO; } +(NSString *)didOfBroadcast:(MHBluetoothBroadcastPackage *)broadcast{ return broadcast.peripheral.identifier.UUIDString ; } + (NSString *)deviceModelOfBroadcast:(MHBluetoothBroadcastPackage *)broadcast{ return XMBand2Model; }
-
-
进入插件后,相关流程参见文档
- MHPluginSDK中有把设备添加到设备列表中的相关方法
- MHBluetoothLE中有蓝牙读写的相关方法
- SDK 提供了一个蓝牙示例插件,见 com.xiaomi.corebledemo.ios 目录
-
如有问题,请联系米家人员
-
获取当前固件最新版本
MHPluginSDK.callSmartHomeAPI("/home/latest_version", {"model":MHPluginSDK.deviceModel}, (response) => { console.log("latest version"+JSON.stringify(response)); });
-
获取固件当前的版本号 通过蓝牙service、character读出当前固件版本号(成功连接的固件sdk会读取一次,通过MHPluginSDK.getDevicePropertyFromMemCache读取version属性可以获得,如果有问题,可以自行通过蓝牙读取)
-
固件下载、解压缩等操作在 MHPluginFS 模块文档中有下载文件、解压缩等的接口
-
读写数据到固件的流程不变,新增了读写hex字符串到设备的便携接口
MHBluetooth模块,writeHexDataWithCallback(hexString, characteristicUUID, serviceUUID, type, callback) AL-[113,)
蓝牙网关设备具有米家 WiFi + BLE 双模通信能力,允许支持米家蓝牙协议的纯 BLE 设备通过其接入互联网。大致原理如下:
更多蓝牙网关信息请参考小米 IoT 开发者平台。
作为支持米家蓝牙协议的纯蓝牙设备,若处于蓝牙网关可扫描的范围内,则认为该蓝牙设备已经与蓝牙网关“连接”,蓝牙网关会实时接收蓝牙设备广播的数据,上报至云端。则:
1,用户通过米家 App 查看该蓝牙设备时,无需跟设备直接建立蓝牙连接,可查看设备上报的历史数据;
2,设备显示为在线,无需手机与设备建立连接。
注意,蓝牙设备“连接”蓝牙网关的前提是,两者处于同一小米账号下。
蓝牙设备插件可以通过 MHPluginSDK
模块中以下接口支持蓝牙网关功能:
该接口可实时判断蓝牙设备是否与蓝牙网关“连接”
参数说明:
mac
蓝牙设备的 mac 地址
callback
返回数据格式为数组,若设备未与蓝牙网关连接则返回 [0]
,若与蓝牙网关连接则返回 [1, gateway_mac]
,gateway_mac 为蓝牙设备“连接”的蓝牙网关的 mac 地址。
示例:
MHPluginSDK.isBtGateWaySubDeviceWithMac(xxxxxxxxxxxx,(res)=>{
if(!res){
// 未连接
return;
}
// 已连接
});
调用米家云端 API ,查询蓝牙设备上报至云端的历史数据。
api 包括 /user/get_user_device_data
读取时间相关数据与/device/batchdevicedatas
读取时间无关数据,请求参数与示例见 MHPluginSDK 模块说明。
打开蓝牙网关设备页面,查看该网关下的子设备。无参数。插件厂商需根据设备实际情况(是否是蓝牙网关设备,是否有固件版本限制等)来决定是否调用该接口。
如遇问题请提交 issue。