FireBLE

FireBLE 是一个面向于打造智能生活的开源平台,以BLE(Bluetooth Low Energy)技术为核心,拥有超低的功耗、不俗的处理能力和广泛的应用场合,专注于更智能、高效率的工作模式,让生活在科技中更安全、方便、快捷。也许您一个不经意的想法与FireBLE擦出的火花,会在这片原野上燎出火焰,甚至燃烧整个世界。

简易防丢器

更新时间:2017-08-08 阅读:2871

项目概述

项目角色定位

在蓝牙协议中,有着两种角色,一种是中心设备(central),一种是外部设备(peripheral). 在本项目中,手机APP扮演的中心设备,防丢器(单片机)扮演的是外部设备.所以我们需要用到的是下图左边的API.

API.jpg

项目原理

蓝牙防丢器:指的是通过蓝牙将防丢器和手机APP建立连接,当手机和防丢器之间的距离超出某个指定的值时,就会对用户进行提醒.

进行距离计算: 要知道蓝牙通信节点(如手机和蓝牙设备)之间的距离,最容易实现的方法是通过读取接收RSSI(Received Signal Strength Indication)值来计算.无线通讯中功率与距离的关系如下:RSSI.jpg其中A可以看作是信号传输1米远时接收信号的功率,n是传播因子(它受障碍,温度和湿度等影响),r是节点之间的距离.当确定了常数A与n的值后,距离r就可以根据PR(dBm)计算出来.

实现过程

定义服务与特征

定义好蓝牙通信所需的服务和特征对应的UUID,如:

#define BATTERY_SERVICE_UUID            @"180F"
#define IMALERT_SERVICE_UUID            @"1802"
#define INTERACTION_SERVICE_UUID        @"CC07"
 
#define BATTERY_CHARACTERISTIC_UUID     @"2A19"
#define ALERT_CHARACTERISTIC_UUID       @"2A06"
#define RECEIVE_CHARACTERISTIC_UUID     @"CD01"
#define SENDCMD_CHARACTERISTIC_UUID     @"CD20"
#define VERSION_CHARACTERISTIC_UUID     @"CD30"

通过蓝牙扫描开启指定服务的设备

CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
 
[centralManager scanForPeripheralsWithServices:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID UUIDWithString:INTERACTION_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };

实现两个重要delegate

CBCentralManagerDelegate

在.h文件中:

@interface TCBleCentralManager : NSObject <CBCentralManagerDelegate>
@property (strong,nonatomic)TCBlePeripheral *blePeripheral; //这个类会实现第二个代理CBPeripheralDelegate

在.m文件中,实现几个代理方法:

(void)centralManagerDidUpdateState:(CBCentralManager *)central
 
{
    //在这个方法中会获得到中心设备的蓝牙状态central.state.
}
 
//这个方法是扫描设备的回调函数
 
(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
 
{
      //所需的设备
      blePeripheral.discoveredPeripheral = peripheral;
      //对符合要求的设备发出连接请求
      [self.centralManager connectPeripheral:peripheral options:nil];
}
 
//设备连接成功会回调这个方法
(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
     //实现外设的代理
     peripheral.delegate = blePeripheral.self;
     //获取对应的服务
     [peripheral discoverServices:@[[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID           UUIDWithString:INTERACTION_SERVICE_UUID]]];
}
 
(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    /**这个方法调用有两种原因:
            一是调用方法(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options失败,
            二是调用方法(void)cancelPeripheralConnection:(CBPeripheral *)peripheral.
            区别在与如果是第一种方法error不为nil,第二种为nil
    */
    //清除设备信息
     [self cleanup: blePeripheral.discoveredPeripheral];
     blePeripheral.discoveredPeripheral = nil;
}
(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    //这个方法是因为调用了(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options超时
    //清除设备信息
     [self cleanup: blePeripheral.discoveredPeripheral];
     blePeripheral.discoveredPeripheral = nil;
}
 
//断开设备并且清除信息
(void)cleanup:(CBPeripheral*)peripheral
{
    // Don't do anything if we're not connected
    if (!peripheral.isConnected)
    {
        return;
    }
 
    // See if we are subscribed to a characteristic on the peripheral
    if (peripheral.services != nil)
    {
        for (CBService *service in peripheral.services)
        {
            if (service.characteristics != nil)
            {
                for (CBCharacteristic *characteristic in service.characteristics)
                {
                    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]])
                    {
                        if (characteristic.isNotifying)
                        {
                            // It is notifying, so unsubscribe
                            [peripheral setNotifyValue:NO forCharacteristic:characteristic];
 
                            // And we're done.
                            return;
                        }
                    }
                }
            }
        }
    }
    // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
    [self.centralManager cancelPeripheralConnection:peripheral];
}

CBPeripheralDelegate

在.h文件中:

@interface TCBlePeripheral : NSObject <CBPeripheralDelegate>
@property (strong,nonatomic) CBPeripheral * discoveredPeripheral;

在.m文件中,实现几个代理方法:

//发现设备服务
 
(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
   //扫描所需服务中所要的特征
   for (CBService *service in peripheral.services)
    {
        if ([service.UUID isEqual:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID]])
        {
            [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]] forService:service];
        }
    }
}
 
//发现服务中的特征(用于通信)
(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    //找到这些特征,并且管理起来,用于后面的通信
    for (CBCharacteristic *characteristic in service.characteristics)
    {
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]])
        {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];//设置为订阅的模式
            batteryCh = characteristic;
        }
    }
}
//更新特征的状态
(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
}
//更新特征获取到的信息值,如电量.
(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    if ([characteristic.UUID.UUIDString compare:batteryCh.UUID.UUIDString] == 0)
    {
        char * value = (char*)[characteristic.value bytes];
        NSLog(@"电量: %@,,%@,%c", stringFromData,characteristic.value,value[0]);
        return;
    }
}
//通过特征主动读取设备信息
[discoveredPeripheral readValueForCharacteristic:characteristic];
 
//通过特征写入设备信息
static int data = 0x04;
 
[discoveredPeripheral writeValue:[[NSData alloc] initWithBytes:&data length:1] forCharacteristic:characteristic type:1];

获取RSSI值

[discoveredPeripheral readRSSI];

对discoveredPeripheral.RSSI.intValue直接使用; readRSSI会回调方法(void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error(IOS5.0后使用,IOS8.0弃用)