# BeaconPlus iOS开发套件说明

  • 持续更新中... ​ 本套SDK仅支持基于miniBeaconPlus固件的设备,不再支持其他公司生产的产品。相对于之前的单一通道设备SDK来说,现在的这一套BeaconSET+ SDK支持的特性更多。当然开发过程中也遇到过诸多问题,我们会在本文档说明设计缘由以及注意事项。所以,请仔细阅读此文档以便尽快上手进行项目开发。

​ 请按需阅读以下每个部分,第一部分我们会说明这套SDK的整体架构,第二部分会帮助开发者上手开发,第三部分会提及开发过程中的注意事项,第四部分可以查阅到错误码的对应说明。

# 设计说明

我们在SDK里把手机对设备的操作分成了两个阶段:广播阶段和连接阶段。为了便于理解,我们先来看看我们都提供了哪些可以操作的类以及它们的职责:

MTCentralManager: 全局管理,可以检查当前手机的蓝牙状态,监听系统的蓝牙状态改变。另外最重要的是可以扫描以及连接到这些设备;

MTPeripheral: 设备实例,当CentralManager发现一个新设备时,会对应为其生成一个MTPeripheral实例,以真实的物理设备为单位,一个设备对应一个MTPeripheral实例。它包括了MTConnectionHandler和MTFrameHandler两个属性(下文会继续描述这两个属性的作用)。

*MTFrameHandler:*广播包解析,这个类可以解析某个设备所广播出来的所有数据包,也就是说,它是扫描阶段的核心,所有由MTCentralManager扫描出来的广播数据都由它来解析成对应的数据帧实例。

*MTConnectionHandler:*连接状态操作,所有连接上设备后发生的操作都是由此类完成,包括监听连接状态改变,读取数据,写入数据等。

*MTSensorHandler:*传感器操作,所有连接上设备后发生的传感器操作都是由此类完成,包括读取温湿度和设置红外参数。

*MinewFrame:*数据帧,每个此类(或者子类)实例都对应一种数据帧,一般会由MTFrameHandler生成,如果设备正在广播多种数据帧,就会生成多个对应的MinewFrame实例。这些实例可以通过MTFrameHandler获取到。

*MTOTAManager:*空中升级,此类只能用来更新设备固件,它操作的是MTConnectionHandler实例。

# 整体架构:

BeaconSET+

# 广播阶段

这个阶段主要是扫描周围的miniBeaconPlus设备和解析这些设备上的广播数据,首先MTCentralManager发起扫描,MTCentralManager会为每一个物理设备生成一个MTPeripheral实例,开发者可以通过它的MTFrameHandler属性拿到关于此设备的所有广播数据。

# 连接阶段

当MTCentralManager扫描到物理设备并生成MTPeripheral实例后,就可以连接到设备,此时针对设备的连接操作都是通过MTConnectionHandler来完成的。

# OTA单独说明

常规的OTA逻辑比较复杂,所以单独封装了MTOTAManager来执行OTA操作,必须在已经和设备建立连接的状态下才能进行。

# 开始上手

# 准备工作

# 开发环境:

  • Xcode9+,由于使用的DFU和Zip框架基于Swift4.0开发,所以请使用Xcode9及更高版本进行开发;

  • iOS8,限制最低系统版本为iOS8;

# 导入到工程

# 手动导入
  1. 将开发套件的三个framework文件:MTBeaconPlus.framework, iOSDFULibrary.framework, Zip.framework拷贝到项目工程目录下,然后添加到工程中,target为当前的工程,然后点“Add”,如下图所示:

add frameworks

  1. 依次找到:“Target” -> General -> Embedded Binaries,点击下面的“+”,将上述3个Framework文件添加进来,同样的,也需要添加到 ”Linked Frameworks and Libraries“,添加完应该如下图:

    make sure frameworks

  2. *如果使用Swift开发,需要添加一个Objective C BridgingHeader .h文件(此处不再赘述),并且在此文件添加:import <MTBeaconPlus/MTBeaconPlus.h>,如果使用Objective C进行开发,在需要的文件的顶端添加:import <MTBeaconPlus/MTBeaconPlus.h>

  3. *如果使用Objective-C开发,则需要在“Target” -> Building Settings -> Always Embed Swift Standard Libraries" 设置为YES。

  4. !!!在iOS10及以上版本,苹果对蓝牙APi添加了权限限制,你需要在工程的info.plist文件里添加一项字符串:Privacy - Bluetooth Peripheral Usage Description - "你的使用描述"。如下图所示:

    bp_access

    1. !!!在iOS13及以上版本,苹果对蓝牙APi添加了权限限制,你需要在工程的info.plist文件里添加一项字符串:Privacy - Bluetooth Always Usage Description - "你的使用描述"。

# 开始开发

# 获取管理类单例

首先开发者需要获取一个管理类单例,并且做好开发者需要的监听:

// 获取管理类单例
MTCentralManager *manager = [MTCentralManager sharedInstance];

// 如果需要监听系统蓝牙状态变化请这样做
// *** 还可以通过state属性主动获取
// *** 仅当state == PowerStatePoweredOn时开发套件才可正常工作
manager.stateBlock = ^(PowerState state) {
     NSLog("当前系统蓝牙状态:%d",state);
};
1
2
3
4
5
6
7
8
9

# 扫描设备

需要通过扫描来发现附近的设备,这样才能获取它们的广播内容,连接并修改设备参数等。

/*
  manager: MTCentralManager的单例
*/

// 执行扫描方法
[manager startScan:^(NSArray<MTPeripheral *> *peris){
  
   // 遍历数组,获取每个设备实例
   // 也可以把它们绑定到UI上,将所有数据显示出来。
    for(NSInteger i = 0; i < peris.count; i ++){
        MTPeripheral *peri = peris[i];
        
        // 获取设备广播阶段实例
        // 部分属性可能为空,请参见“注意事项”
        MTFrameHandler *framer = peri.framer; 
        NSString *name = framer.name;          // 设备名, 可能为空
        NSInteger rssi = framer.rssi;          // rssi
        NSInteger battery = framer.battery;    // 电池,可能为空
        NSString *mac = framer.mac;            // mac地址, 可能为空
        NSArray *frames = framer.advFrames;    // 设备广播的所有数据帧(iBeacon,UID,URL...)
    }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

另外,你可以在任何时候停止扫描任务。

/*
  manager: MTCentralManager的单例
*/

// 通过这种方式停止扫描
[manager stopScan];
1
2
3
4
5
6

通过以上方式我们就可以获取到设备在广播阶段的所有相关数据,进一步的,想要从frameHandler里获取到所有的数据帧,可以参考以下代码示例:

/*
  aFrameHandler: MTFrameHandler实例,
*/

NSArray *frames = aFrameHandler.advFrames;
for (NSInteger i = 0; i < frames.count; i ++){
    MinewFrame *frame = frames[i];
    
    switch(frame.frameType){
      case FrameiBeacon:
        {
          MinewiBeacon *bea = (MinewiBeacon *)frame;
          NSLog(@"iBeacon:%@, %ld, %ld, %@",bea.uuid, bea.major, bea.minor, bea.lastUpdate);
        }
           break;
        
      case FrameUID:
        {
           MinewUID *uid = (MinewUID *)frame;
           NSLog(@"UID:%@, %@, %ld, %@", uid.namespaceId, uid.instanceId, uid.txPower, uid.lastUpdate);
        }
           break;
        
        case FrameDeviceInfo:
        {
            MinewDeviceInfo *info = (MinewDeviceInfo *)frame;
            NSLog(@"DeviceInfo: %ld, %@, %@, %@", (long)info.battery, info.mac, info.name, info.lastUpdate);
        }
            break;
        
        case FrameTLM:
        {
            MinewTLM *tlm = (MinewTLM *)frame;
            NSLog(@"TLM: %ld, %f, %ld, %ld, %@", tlm.batteryVol, tlm.temperature, tlm.advCount, (long)tlm.secCount, tlm.lastUpdate);
        }
            break;
        
        case FrameURL:
        {
            MinewURL *url = (MinewURL *)frame;
            NSLog(@"URL: %ld, %@, %@", url.txPower, url.urlString, url.lastUpdate);
        }
            break;
        
        case FrameLineBeacon:
        {
            MinewLineBeacon *lineBeacon = (MinewLineBeacon *)frame;
            // 如果需要获取 vendorKey和lotKey,需要连接后进行操作,具体操作请参考“获取各通道数据”部分。
            NSLog(@"LineBeacon:%@, %@, %@, %ld, %@", lineBeacon.hwId, lineBeacon.authenticationCode, lineBeacon.timestamp, lineBeacon.txPower, lineBeacon.lastUpdate);
        }
            break;
        
            
            
      /*
         更多类型,请自行处理
      */
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

**重要提示:**在获取所有的传感器数据时,如果值等于MTNAValue(我们定义的无效值常量,在"MTPublicHeader.h“文件中),表示这个数据是无效的。所有的传感器实例(MinewHTSensor,MinewLightSensor,MinewAccSensor,MinewForceSensor,MinewPIRSensor)都有这种情况。

请参考以下代码:

/*
    aHT: MinewHTSensor实例
    aLight: MinewLightSensor实例
    aAcc: MinewAccSensor实例
    aForce: MinewForceSensor实例
    aPIR: MinewPIRSensor实例
*/

if (aHT.temperature == MTNAValue) {
    NSLog(@"this value is not available.")
}

if (aLight.luxValue == MTNAValue) {
    NSLog(@"this value is not available.")
}

if (aAcc.XAxis) {
    NSLog(@"this value is not available.")
}

if (aForce.gramValue) {
    NSLog(@"this value is not available.")
}

if (aPIR.gramValue) {
    NSLog(@"this value is not available.")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 连接设备

要对设备进一步操作(修改参数,OTA),需要先连接到设备。由于有些设备在连接时可能需要密码验证,所以验证密码的Block为必须实现,否则将引起Crash!!! 如下代码所示:

/*
  manager: MTCentralManager的单例
  aMTPeripheral: MTPeripheral实例
*/

// 监听设备连接状态改变
aMTPeripheral.connector.statusChangeHandler = ^(ConnectionStatus status, NSError *error) {
    
    /*
     typedef NS_ENUM(NSInteger, ConnectionStatus) {
         StatusConnectFailed = -2,
         StatusDisconnected = -1,
         StatusUndifined = 0,
         StatusConnecting,
         StatusConnected,
         StatusReadingInfo,
         StatusDeviceValidating,
         StatusPasswordValidating,
         StatusSycingTime,
         StatusReadingConnectable,
         StatusReadingFeature,
         StatusReadingFrames,
         StatusReadingTriggers,
         StatusReadingSensorInfo,
         StatusCompleted,
     };
     */
    
    // 整个连接过程需要经过多个中间状态,如果遇到错误,会通过error抛出
    // 只有当status == StatusCompleted时,才算是连接成功
  
};

// 连接到设备
// 需要一个MTPeripheral实例作为参数
// !!!:特别提醒:passwordRequire为必须实现的
[manager connectToPeripheral:aMTPeripheral passwordRequire:^(MTPasswordBlock passwordBlock){
    // 给定一个8位长度的密码,
    // !!! 实际开发中应该从UITextField读取输入的内容作为密码。
    NSString *password = @"minew123";
    passwordBlock(password);
}];

// 断开某个设备的连接状态
[manager disconnectFromPeriperal:aMTPeripheral];

/* 

**/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 获取基本信息

成功连接到设备后,就可以获取设备信息以及修改设备参数了。我们先来看看怎么获取各种基础数据。

/*
   aMTPeripheral: MTPeripheral实例
*/

MTConnectionHandler *con = aMTPeripheral.connector;

ConnectionStatus conSte = con.status;  // 当前的设备连接状态
NSDictionary *infoDict = con.infoDict; // 设备信息,例如:(Firmware Version: 0.9.1);
NSString *mac = con.macString; // mac地址;
Connectable able = con.connectable; // 标记设备是否可以连接,None未知,No不可连,Yes可连
Version version = con.version; // 固件版本枚举,方便处理版本号区分;
PasswordStatus pwdStatus = con.passwordStatus; // 连接时是否需要密码,None不需要,Require需要


MTConnectionFeature *feature = con.feature; // 设备特性;
NSInteger slotAtitude = feature.slotAtitude; // 设备的广播通道数量,可以根据此动态生成UI;
FeatureSupported feaSup = feature.featureSupported; // 可以调节参数类型:none不可调,adv可调,txpower可调,adv/txpower均可调
NSArray<NSNumber *> *supFrames = feature.supportedSlots; // 支持的广播帧类型(多种)
NSArray<NSNumber *> *supTxpower = feature.supportedTxpowers; // 支持的Txpower(多档位)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

PS: MTConnectionHandlerVersion属性说明:

Versoin值来自设备的固件版本号,可以通过检查Version的值来判断当前设备支持的功能:
 
// 初始化值 
VersionUndefined

// 基础版本,仅支持基础功能
VersionBase

// 此版本及以上支持自定义连接密码 / 设备信息广播帧
Version0_9_8

// 此版本及以上支持远程关机命令
Version0_9_9

// 此版本及以上开始支持触发器
Version2_0_0

// 此版本及以上开始支持带广播设置的触发器配置
Version2_2_60

// 理想值,支持所有特性。
VersionMax = 1000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 获取各通道数据

接下来可以获取每个通道对应的参数数据,之所以单独讲这部分,是因为所有与修改相关的内容全部在这里。

在阅读代码之前,我们先来了解通道的概念:通道相当于一个广播工具,它不管里面是什么内容,只管把内容广播出来,例如一个6通道的设备可能是这样的:

通道序号 0 1 2 3 4 5
广播内容 iBeacon TLM UID URL HTSensor None
广播间隔(ms) 1000 2000 500 900 3000 0
RSSI@0/1m(dbm) -1 0 -4 -10 -3 0
信号强度(dbm) 4 0 -4 4 0 0

上表的意思是,第0个通道广播iBeacon数据,第1个通道广播TLM数据,…,第5个通道不广播任何数据。它们每个都有独立的广播间隔,信号强度和校准值,互相之间没有关系也不产生任何影响。

PS:校准值(RSSI@0/1m)指的是手机在设备0/1m(iBeacon为1,其它为0)处的信号强度。

接下来我们来看下怎么获取设备的通道数据。

/*
    con: MTConnectionHandler实例
*/

// 当前设备每一个通道对应的数据帧
// 此数组的数量和通道数量保持一致(也就是feature.slotAtitude)
// 按照通道顺序严格排序,比如:0. -> MinewiBeacon,1. -> MinewUID ...
NSArray<MinewFrame *> *frames = con.allFrames;

/*
   假如第3个通道为iBeacon数据,第4个通道数据为UID,
   我们尝试解析第3个通道的数据。
*/

// 由于默认指针是MinewFrame(MinewiBeacon的父级)类型,需要做一下转换。

// 获取第3个通道的数据帧
MinewFrame *frame = frames[2];

// 确认此通道是iBeacon类型,如果类型确认,可以不需要做这一步判断
switch (frame.frameType) {
case FrameiBeacon:
{
    MinewiBeacon *iBeacon = (MinewiBeacon *)frame;

    // iBeacon数据
    NSString *uuid = iBeacon.uuid;   // 获取uuid
    NSInteger major = iBeacon.major;  // 获取major
    NSInteger minor = iBeacon.minor;  // 获取minor

    // 所处通道的参数
    NSInteger slotNumber = iBeacon.slotNumber;           // 第几通道
    NSInteger slotAdvInterval = iBeacon.slotAdvInterval; // 此通道的广播间隔
    NSInteger slotAdvTxpower = iBeacon.slotAdvTxpower;   // 此通道的信号校准值 iBeacon:RSSI@1m others: RSSI@0m
    NSInteger slotRadioTxpower = iBeacon.slotRadioTxpower; // 此通道信号强度
}
    break;
    
case FrameURL:
{
    MinewURL *url = (MinewURL *)frame;
    NSString *urlStr = url.urlString;
    
    // 所处通道的参数获取方式均一致
}
    break;
    
case FrameUID:
{
    MinewUID *uid = (MinewUID *)frame;
    NSString *namespaceId = uid.namespaceId;
    NSString *instanceId = uid.instanceId;
    
    // 所处通道的参数获取方式均一致
}
    break;

case FrameLineBeacon:
{
    // LineBeacon(获取方式较为特殊)
    MTLineBeaconData *lineBeaconData = self.currentPeripheral.connector.slotHandler.slotFrameDataDic[FrameTypeString(FrameLineBeacon)];
    NSString *hwid = lineBeaconData.hwId;
    NSString *vendorKey = lineBeaconData.vendorKey;
    NSString *lotKey = lineBeaconData.lotKey;
    
    // 所处通道的参数获取方式均一致
}
    break;
/*
   如有需要,可自行处理其他类型的数据。 
*/
default:
    break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

你可以使用同样的方式来解析其它所有通道,值得注意的是,当frameType == FrameNone 时,说明此通道没有广播数据。

# 修改通道数据

通过我们的开发套件,开发者可以自由的修改每个通道的广播数据。

我们区分了静态数据帧和动态数据帧,静态数据帧指的是广播数据不会发生变化的:iBeacon,UID,URL等等,动态数据帧指的是广播数据不定时发生变化的:TLM,各类传感器数据等。

可以通过下面的参考代码实现。

/*
   aConnectionHandler: MTConnectionHandler实例
*/

// 生成一个uid实例
MinewUID *uid = [[MinewUID alloc]init];

// 配置uid的namespaceId和instanceId参数
uid.namespaceId = @"0123456789abdcdcba12";
uid.instanceId = @"0123456789dc";

// 通道相关配置
uid.slot = 1;  // 设置想要配置的通道序号
uid.slotAdvInterval = 600;  // 配置这个通道的广播间隔
uid.slotAdvTxpower = -3;    // 配置这个通道的信号校准值 RSSI@0m
uid.slotRadioTxpower = 4;   // 配置这个通道的广播功率

// 写入到设备
// 详情:1.把1通道设置为UID广播,namespaceId:0123456789abdcdcba12,instanceId:0123456789dc
//      2.设置1通道的广播间隔为600ms,RSSI@0m为-3dbm,广播功率为:4dbm
[aConnectionHandler writeFrame:uid completion:^(BOOL success, NSError *error){
     if (success) {
        NSLog(@"write frame to device successfully.");   
     } 
     else if(error) {
        NSLog(@"Error:%@", error)
     }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

请注意,以下通道参数设置必须在范围内:

  • 广播间隔: 100 - 5000 (ms)
  • RSSI@0m: -127 - 0 (dbm)

重要提醒: 广播功率是档位值, 例如: -8, -4, 0, 4. 你可以通过"MTConnectionHandler"的feature属性里获取到当前设备支持的所有广播功率档位:

/*
   feature: MTConnectionHandler实例的属性.
*/

// 获取当前设备支持的所有广播功率档位.
NSArray<NSNumber *> *supTx = feature.supportedTxpowers
1
2
3
4
5
6

你可以通过相同的方式修改任何一个通道的广播数据,如果需要关闭某个通道,只需要创建一个frameType=FrameNone的MinewFrame对象写入到设备即可,当然,别忘了设置通道序号。

# 设置 LineBeacon

LineBeacon 帧需要在写入帧数据的方法之后,另外调用以下两个方法设置LineBeacon的hwid,vendorKey和lotKey

// lotKey:16位, hwid:10位,vendorKey:8位,包含a-f/A-F/0-9

// 设置 LineBeacon 的 lotKey
[self.currentPeripheral.connector.slotHandler lineBeaconSetLotkey:@"0011223344556677" completion:^(BOOL success) {
    if (success) {
        NSLog(@"Set LineBeacon's lotKey success");
    } else {
        NSLog(@"Set LineBeacon's lotKey failed");
    }
}];

// 设置 LineBeacon 的 hwid 和 vendorKey
[self.currentPeripheral.connector.slotHandler lineBeaconSetHWID:@"0011223344" VendorKey:@"00112233" completion:^(BOOL success) {
    if (success) {
        NSLog(@"Set LineBeacon's hwid and vendorKey success");
    } else {
        NSLog(@"Set LineBeacon's hwid and vendorKey failed");
    }
}];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 修改设备全局参数

设备全局参数指的是设备级的一些特性,比如:配置设备是否可连接,是否需要密码,恢复出厂等。

可以通过以下代码示例参考。

/*
   aConnectionHandler: MTConnectionHandler实例
*/
// 恢复出厂设置
[aConnectionHandler resetFactorySettings:^(BOOL success, NSError *error){
    if(success){
        NSLog(@"Operation success!");
    }
    else {
        NSLog(@"Opertion failed!");
    }
}];

// 更新设备可连接设置
// YES为可连接,NO不可连接,
// 配置设备不可连接后,可以通过按下设备上的按钮再次连接到设备。
// !!!:如果设备上没有按钮,且把设备配置为不可连后,设备将无法再次被连接。
[aConnectionHandler updateConnectable:YES completion:^(BOOL success, NSError *error){
    if(success){
        NSLog(@"Operation success!");
    }
    else {
        NSLog(@"Opertion failed!");
    }
}];

// 修改/增加密码
// !!!: 只能设置8位密码,数字或英文字母;
// 设备没有密码时,会添加密码,设备有密码时,会更新密码。
[aConnectinoHandler modifyPassword:@"12345678" completion:^(BOOL success, NSError *error){
    if(success){
        NSLog(@"Operation success!");
    }
    else {
        NSLog(@"Opertion failed!");
    }
}];

// 移除密码
[aConnectionHandler removePassword:^(BOOL success, NSError *error){
    if(success){
        NSLog(@"Operation success!");
    }
    else {
        NSLog(@"Opertion failed!");
    }
}];

// 远程关闭设备
// !!!:请确认设备上有按钮,可以通过按下按钮的方式重启,否则关闭后无法重启设备。另外Model Number如果是 Beacon Plus-BL,那么关闭设备会失效,不支持该功能。
[aConnectionHandler poweroff:^(BOOL success, NSError *error){
    if(success){
        NSLog(@"Operation success!");
    }
    else {
        NSLog(@"Opertion failed!");
    }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 设备上的传感器数据

BeaconPlus设备整合了温湿度,光感,加速度等多种传感器,目前我们提供了温湿度/六轴/磁力计/大气压力历史数据的读取接口和红外传感器参数设置接口。

请确认此设备带有温湿度传感器,否则无法正确获取数据。

可以通过以下代码示例参考。

/*
   aConnectionHandler: MTConnectionHandler实例
*/

// 从设备上读取温湿度数据
[aConnectionHandler.sensorHandler readSensorHistory:^(MTSensorData *data){
   
   NSInteger time = ((MTSensorHTData *)data).timestamp;   // 此数据的Unix时间戳;
   double temp = ((MTSensorHTData *)data).temperature;    // 温度数据;
   double humi = ((MTSensorHTData *)data).humidity;       // 湿度数据;
   NSInteger index = ((MTSensorHTData *)data).index;      // 此数据的编号;
  
   if (((MTSensorHTData *)data).endStatus == EndStatusNone){
       NSLog(@"there is no data.");
   }
   else if (((MTSensorHTData *)data).endStatus == EndStatusSuccess) {
       NSLog(@"sensor data sync successfully!");
   }
   else if (((MTSensorHTData *)data).endStatus == EndStatusError) {
       NSLog(@"something wrong in syncing progress.");   
   }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

你可以用表格或者曲线的方式把这些数据生动的呈现出来。

请确认此设备带有红外传感器,否则无法正确获取数据。

可以通过以下代码示例参考。

/*
   aConnectionHandler: MTConnectionHandler实例
   aRepeat:是否允许重复触发
   aTime:触发时间,过了触发时间后才可以再次触发红外传感器
*/

// 设置设备红外传感器数据
[aConnectionHandler.sensorHandler pirSet:aRepeat andDelayTime:aTime completion:^(MTSensorData *data){
   
    if (data.status) {
        NSLog(@"success");
    }
    else {
        NSLog(@"failed");
    }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 配置触发器

BeaconPlus设备加入了触发器功能,你可以给每个通道独立的配置触发器,仅当满足触发条件时设备才会开启对应通道进行广播,否则,对应通道将会一直处于关闭状态。

可以通过以下代码示例参考。

NSInteger slotAtitude = 2;                 // 目标通道:2
TriggerType type = TriggerTypeTempAbove;   // 触发条件:温度高于
NSInteger value = 10;                      // 触发值:10

MTTriggerData *trigger = [[MTTriggerData alloc] initWithSlot:slotAtitude paramSupport:true triggerType:type value:value];

// 如果需要触发后持续广播
trigger.always = true;        // 触发后是否持续广播
trigger.advInterval = 100;    // 广播时间间隔
trigger.radioTxpower = -20;   // 广播信号强度

// 写入到设备
[self.connectedPeripheral.connector writeTrigger:trigger completion:^(BOOL success) {
    if(success){
        NSLog(@"write trigger successfully!");
    }
    else {
        NSLog(@"write trigger failed!");
    }
}];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 振动传感器的其他相关配置

设置和查询是否开启振动,开启振动才会收到振动传感器的广播帧,关闭振动则停止广播振动传感器广播帧

   
 	//    MTVibrationTypeOpen,
	//    MTVibrationTypeClose,
	//    MTVibrationTypeError,
  [self.currentPeripheral.connector.sensorHandler setVibrationStatus:MTVibrationTypeOpen CompletionHandler:^(BOOL isSuccess) {

  }];


  [self.currentPeripheral.connector.sensorHandler queryVibrationStatu:^(BOOL isSuccess, MTVibrationType type) {

  }];
1
2
3
4
5
6
7
8
9
10
11
12

设置和查询振动传感器灵敏度

    //    MTSensitivityTypeSuperHigh,
    //    MTSensitivityTypeHigh,
    //    MTSensitivityTypeMiddle,
    //    MTSensitivityTypeLow,
    //    MTSensitivityTypeSuperLow,
    [self.currentPeripheral.connector.sensorHandler setSensitivity:MTSensitivityTypeHigh CompletionHandler:^(BOOL isSuccess) {
        
    }];
    

    [self.currentPeripheral.connector.sensorHandler querySensitivity:^(BOOL isSuccess, MTSensitivityType type) {
        
    }];
1
2
3
4
5
6
7
8
9
10
11
12
13

设置和查询振动传感器警告时间区间,开始时间需小于结束时间,精确到时分。 另外,参数需要进行计算,以秒为单位,比如早上六点十分到晚上十点,startTime = 6 * 3600 + 10 * 60 = 22200,endTime = 22 * 3600 + 0 * 60 = 79200.

    // timeZone = hours*3600 + minutes*60
    // 22200 = 6*3600 + 10*60 = 6:30
    [self.currentPeripheral.connector.sensorHandler setFirstAlarmTimeIntervalWithAlarmStatus:MTVibrationTypeOpen StartTime:22200 EndTime:79200 CompletionHandler:^(BOOL isSuccess) {
        
    }];
    
    [self.currentPeripheral.connector.sensorHandler queryFirstAlarmTimeInterval:^(BOOL isSuccess, MTVibrationType type, uint32_t startTime, uint32_t endTime) {
        NSLog(@"vibrationType:%@, startTime:%dhour %dminute, endTime:%dhour %dminute", type == MTVibrationTypeOpen ? @"Open" : @"Close or Error", startTime/3600, startTime%3600/60, endTime/3600, endTime%3600/60);
    }];
    
    [self.currentPeripheral.connector.sensorHandler setSecondAlarmTimeIntervalWithAlarmStatus:MTVibrationTypeOpen StartTime:22200 EndTime:79200 CompletionHandler:^(BOOL isSuccess) {
        
    }];
    
    [self.currentPeripheral.connector.sensorHandler querySecondAlarmTimeInterval:^(BOOL isSuccess, MTVibrationType type, uint32_t startTime, uint32_t endTime) {
        
    }];
    
    [self.currentPeripheral.connector.sensorHandler setThirdAlarmTimeIntervalWithAlarmStatus:MTVibrationTypeOpen StartTime:22200 EndTime:79200 CompletionHandler:^(BOOL isSuccess) {
        
    }];
    
    [self.currentPeripheral.connector.sensorHandler queryThirdAlarmTimeInterval:^(BOOL isSuccess, MTVibrationType type, uint32_t startTime, uint32_t endTime) {
        
    }];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 设置广播速率

型号为 MBM01 的设备,并且固件版本为 2.5.x 时,可对帧通道设置蓝牙 4.0 1Mbps 广播速率或者蓝牙 5.0 125Kbps 广播速率。

六个广播通道每个通道占一个值, 当值设置为 0 代表蓝牙 4.2 1Mbps 的广播模式, 当值设置为 1 代表蓝牙 5.0 125Kbps 的广播模式。

需要注意的是,iOS 目前无法获取到广播频率为 125Kbps 广播速率的广播包,安卓无此问题。即 iOS 上设置蓝牙 5.0 广播速率为 125Kbps 的帧通道,设置完成后,在 iPhone 上无法扫描到该帧,但是该帧在安卓上可以扫描到。

    [self.currentPeripheral.connector.sensorHandler queryBroadcastSpeed:^(BOOL isSuccess, NSArray * _Nonnull broadcastSpeedOfSlotArray) {
        NSLog(@"第一个通道的广播速率是%@", [broadcastSpeedOfSlotArray[0] intValue] == 1 ? @"蓝牙5.0 125k" : @"蓝牙4.0 1M");
    }];
    
    // 设置广播速率时,传入的数组有六个值,每个值对应六个通道。 0 表示蓝牙 4.0 广播速率为 1M, 1 表示蓝牙 5.0 广播速率为 125Kbps。比如设置第一和第二通道为 125Kbps 广播,其他通道设置为 1Mbps 广播,那么设置如下:
    [self.currentPeripheral.connector.sensorHandler settingBroadcastSpeed:@[@1,@1,@0,@0,@0,@0] CompletionHandler:^(BOOL isSuccess) {
        
    }];
1
2
3
4
5
6
7
8

# 设置 Acc 传感器可配置固件的参数配置项

此功能属于定制固件专属配套功能,使用前请咨询相关业务人员。

Acc 传感器可配置固件,可设置的参数配置项。

ODR ( 输出速率 ) :

description value
1Hz 0
10Hz 1
25Hz 2
50Hz 3
100Hz 4
200Hz 5
400Hz 6
1600Hz(low power) 7
1344HZ (HR/normal) /5000HZ(low power) 8

wakeup_threshold ( 唤醒阈值 mg ) : 0 ~ 2000

wakeup_duration ( 唤醒持续时间 ms ) : 0 ~ 127000

    [self.currentPeripheral.connector.sensorHandler queryAccSensorParameterWithCompletionHandler:^(BOOL isSuccess, NSInteger odr, NSInteger wakeupThreshold, NSInteger wakeupDuration) {
        
    }];
    
    [self.currentPeripheral.connector.sensorHandler setAccSensorParameterWithOdr:0 WakeupThreshold:200 WakeupDuration:1000 CompletionHandler:^(BOOL isSuccess) {
        
    }];
1
2
3
4
5
6
7

现在,你可以参考以上示例进行开发了。

# 注意事项

  1. 在开发过程中你可能会发现,持续扫描一段时间,有些设备会出现多个MTPeripheral实例。关于这一点,我们咨询过苹果工程师。得到的答复是在目前的iOS平台下,CoreBluetooth对多通道广播(特别是广播数据在变化)设备并不友好。

    iOS11中此问题已不再存在。

  2. 在扫描过程中,有些属性可能是无法获取的,特别是mac地址(iOS平台下的限制),如果当前设备广播了DeviceInfo数据帧,那么name,mac地址,电池都是可以获取到的。

  3. 当你成功连接到设备后,固件最多只保持5分钟连接。然后设备端会主动断开连接。

  4. 如果添加SDK之后,运行显示无法找到路径,可以在 General -> Frameworks,Libraries,and Embedded Content ,把包删除再重新添加一次即可。

# 其他

BeaconPlus SDK 同样运用于我司 BeaconSET+ app,如需更直观的了解我司 beaconPlus 设备以及SDK相对应的功能,也可以下载 BeaconSET+ app 进行了解。(提示:BeaconSET+ app和 BeaconPlus SDK 需要和我司生产的设备配套使用)

# 文档版本记录

  • 2017.10.11 v1.0 初版;
  • 2019.01.07 v1.1 第二版;
  • 2019.07.11 v1.2 修改了 poweroff 方法;
  • 2020.03.27 v1.10.0添加 LineBeacon;
  • 2020.07.27 v1.10.1 优化 LineBeacon 帧的获取和设置
  • 2020.10.27 v1.10.2 每个广播帧新增 lastUpdate 属性
  • 2021.4.21 v1.11.0 新增六轴/磁力计/大气压力传感器
  • 2021.4.28 v1.11.1 新增振动传感器
  • 2021.09.16 v1.13.0 新增红外传感器(合并B9-X)
  • 2021.10.9 v1.14.0 新增设置蓝牙5.0广播速率
  • 2021.12.27 v1.14.1 新增适配加速度传感器可配置固件的参数配置项
  • 2022.5.9 v1.15.0 新增防拆帧
  • 2022.6.1 v1.16.0 新增 IN100 广播帧 MinewMBeaconInfo
  • 2023.11.13 v1.17.0 修复WriteFrame崩溃;优化支持后台扫描
上次更新:: 2024/4/12 09:45:36