ios 蓝牙开门-倾城孤月

//首先,定义一个蓝牙操作类

//

//  LSBuzzBTmanager.h

//  gene

//

//  Created by lollipop on 2017/4/7.

//  Copyright © 2017年 lesports. All rights reserved.

//

 

#import <Foundation/Foundation.h>

#import <CoreBluetooth/CoreBluetooth.h>

 

// 错误类型,后续根据厂商加上其他错误

typedef NS_ENUM(NSInteger,BuzzResult) {

    BuzzBTSuccess = 0,  // 成功

    BuzzBTFail,         // 失败

    BuzzBTInvalid,      // 目前蓝牙不可用

    BuzzTimeout,        // 此标志位只说明超时,并不说明没有搜到结果

};

 

typedef void (^LSBikeFailedBlock)(NSError *error);

typedef void (^LSBikeResultBlock)(BOOL result, NSError *error);

 

@protocol LSBuzzBTmanagerDelegate <NSObject>

 

 

/*

 * @descripe 当前蓝牙是否可用

 * @param available 当前蓝牙是否可用

 */

- (void)centralManagerDidUpdateState:(BOOL)available;

 

/*

 * @descripe 搜到蓝牙设备的回调,每次搜到一个新设备都会回调

 * @param isFinish 搜索是否结束

 * @param list 搜索当前搜索结果

 * @param error 参考BuzzError

 */

- (void)fetchDevice:(BOOL)isFinish device:(NSArray *)list apack:(NSArray *)adpacklist withResult:(BuzzResult)error;

 

/*

 * @descripe 连接制定蓝牙设备结果的回调

 * @param error 参考BuzzError

 */

- (void)connectResult:(BuzzResult)result withError:(NSError *)error;

 

/*

 * @descripe 连接被断开,被动断开或者主动断开

 * @param error 参考BuzzError

 */

- (void)disConnectResult:(BuzzResult)result withError:(NSError *)error;

 

/*

 * @descripe 连接制定蓝牙设备结果的回调(成功)

 * @param error 参考BuzzError

 */

- (void)hasconnectResult:(BuzzResult)result withError:(NSError *)error;

 

@end

 

 

@interface LSBuzzBTmanager : NSObject

 

@property (nonatomic, weak)  id<LSBuzzBTmanagerDelegate> delegate; // 部分回调

 

@property (nonatomic,assign) NSInteger scanTimeInterval;// 扫描时间

 

@property (nonatomic,strong) NSMutableArray *rssiarray;// 信号强度

 

 

// 单例

+ (instancetype)sharedInstance;

 

/*

 *

 * 搜索并连接指定的蓝牙设备

 *

 */

- (BOOL)FinddevFiter:(BOOL)pp;//查找设备,pp为YES表示开uuid过滤,NO表示关闭

 

- (void)stopSearchDevice;//停止扫描设备

 

- (void)connectBuzzard:(CBPeripheral *)peripheral;//连接某项蓝牙设备

 

- (void)disconnectBuzzard:(CBPeripheral *)peripheral;//与某项设备断开连接

 

- (void)writeValue:(NSString *)command option:(NSString *)option;

@end

 

 

//.m文件如下

//

//  LSBuzzBTmanager.m

//  gene

//

//  Created by lollipop on 2017/4/7.

//  Copyright © 2017年 lesports. All rights reserved.

//

 

#import "LSBuzzBTmanager.h"

#import "kbConsoleLog.h"

 

 

#define UUID_CONTROL_SERVICE            @"FEE0"

#define UUID_LISTEN_CHARACTERISTICS     @"FEE1"//写

@interface LSBuzzBTmanager() <CBCentralManagerDelegate,CBPeripheralDelegate> {

    

    CBCentralManager *centerManager;

    CBPeripheral *activePeripheral;

    CBCharacteristic *readCharacteristic;

    CBCharacteristic *controlCharacteristic;

}

 

@property (nonatomic,strong) NSMutableArray *devLists;

@property (nonatomic,strong) NSMutableArray *adpackLists;

 

@end

 

@implementation LSBuzzBTmanager

 

+ (instancetype)sharedInstance {

    static LSBuzzBTmanager *_sharedInstance = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _sharedInstance = [[LSBuzzBTmanager alloc] init];

    });

    return _sharedInstance;

}

 

- (instancetype)init {

    if (self = [super init]) {

        centerManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];

    }

    return self;

}

 

#pragma mark 搜索蓝牙设备相关

- (BOOL)FinddevFiter:(BOOL)ppp {

    // 蓝牙不可用

    if (centerManager.state != CBManagerStatePoweredOn) {

        if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {

            [_delegate fetchDevice:NO device:nil apack:nil withResult:BuzzBTSuccess];

        }

        return NO;

    }

    

    // 开始搜索

    NSArray *serviceUUIDs = nil;

    if (ppp) {  // 过滤

//        serviceUUIDs = @[[CBUUID UUIDWithString:@""]];

    }

    [centerManager scanForPeripheralsWithServices:serviceUUIDs options:nil];

    if (_scanTimeInterval == 0) {

        _scanTimeInterval = 20;

    }

    // 先取消之前的延时

    [LSBuzzBTmanager cancelPreviousPerformRequestsWithTarget:self selector:@selector(scanTimeOut) object:self];

    // 重新执行超时

    [self performSelector:@selector(scanTimeOut) withObject:self afterDelay:_scanTimeInterval];

    return YES;

}

 

- (void)stopSearchDevice {

    [centerManager stopScan];

}

 

 

- (void)connectBuzzard:(CBPeripheral *)peripheral {

    [centerManager connectPeripheral:peripheral options:nil];

}

 

- (void)disconnectBuzzard:(CBPeripheral *)peripheral {

    [centerManager cancelPeripheralConnection:peripheral];

    activePeripheral = nil;

//    [HintView hintViewWithMessage:@"断开连接"];

}

 

- (void)scanTimeOut {

    [centerManager stopScan];

    if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {

        [_delegate fetchDevice:NO device:_devLists apack:self.adpackLists withResult:BuzzBTSuccess];

    }

}

 

- (void)writeValue:(NSString *)command option:(NSString *)option{

    

    if (activePeripheral.state == CBPeripheralStateConnected) {

  

    }else if (activePeripheral.state == CBPeripheralStateConnecting){

        [HintView hintViewWithMessage:@"正在连接"];

        return;

    }else if (activePeripheral.state == CBPeripheralStateDisconnected){

       [HintView hintViewWithMessage:@"peripheral disconnected"];

        return;

    }else if (activePeripheral.state == CBPeripheralStateDisconnecting){

        [HintView hintViewWithMessage:@"peripheral disconnecting"];

        return;

    }

 

    NSData *data;

    if (option.length > 0) {

        data = [self command:command withOption:option];

    } else {

        data = [self dataFromHexString:command];

    }

    NSString *msg = [NSString stringWithFormat:@"Write command %@ on peripheral %@(%@)", data, activePeripheral.name, activePeripheral.identifier];

    NSLogK(msg);

    TDLog(@"controlCharacteristic is %@",controlCharacteristic);

    if (controlCharacteristic==nil) {

        [HintView hintViewWithMessage:@"未找到该设备"];

        return;

    }

 

    [activePeripheral writeValue:data forCharacteristic:controlCharacteristic type:CBCharacteristicWriteWithoutResponse];

 

}

 

#pragma mark - getter

- (NSMutableArray *)devLists{

    if (!_devLists) {

        _devLists = [[NSMutableArray alloc] init];

    }

    return _devLists;

}

- (NSMutableArray *)adpackLists{

    if (!_adpackLists) {

        _adpackLists = [[NSMutableArray alloc] init];

    }

    return _adpackLists;

}

- (NSMutableArray *)rssiarray{

    if (!_rssiarray) {

        _rssiarray = [[NSMutableArray alloc] init];

    }

    return _rssiarray;

}

 

#pragma mark CBCentralManagerDelegate

- (void)centralManagerDidUpdateState:(CBCentralManager *)central{

    BOOL isAvaliable = NO;

    if (central.state == CBManagerStatePoweredOn) {

        isAvaliable = YES;

    }

    if (_delegate && [_delegate respondsToSelector:@selector(centralManagerDidUpdateState:)]) {

        [_delegate centralManagerDidUpdateState:isAvaliable];

    }

}

// 扫描到设备

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {

 

    if (!peripheral.name ) {

        return;

    }

    if (peripheral.name == 0) {

        return;

    }

    // 如果已经被搜索,就不新加入

    if ([self.devLists containsObject:peripheral]) {

        return;

    }

    

    // 1.信号过滤,信号太弱连不上

    // 2.名称过滤

    // 根据startScanBuzzard方法中扫描结果 再看是否需要增加过滤逻辑

    [self.devLists addObject:peripheral];

    NSData *data=advertisementData[@"kCBAdvDataManufacturerData"];

    NSString *adpackstr= [self dataToHex:data];

    [self.adpackLists addObject:adpackstr];

 

    [self.rssiarray addObject:[NSString stringWithFormat:@"%@",RSSI]];

    if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {

        [_delegate fetchDevice:NO device:_devLists apack:self.adpackLists withResult:BuzzBTSuccess];

    }

}

 

// 连接设备

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {

 

    activePeripheral = peripheral;

 

    if (_delegate && [_delegate respondsToSelector:@selector(hasconnectResult:withError:)]) {

        [_delegate hasconnectResult:BuzzBTSuccess withError:nil];

    }

    NSArray *services = nil;// @[[CBUUID UUIDWithString:@""]];

    activePeripheral.delegate = self;

    [activePeripheral discoverServices:services];

}

 

// 连接设备失败

-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {

    NSString *msg = [NSString stringWithFormat:@"-didFailToConnectPeripheral-%@",peripheral.name];

    NSLogK(msg);

    if (_delegate && [_delegate respondsToSelector:@selector(connectResult:withError:)]) {

        [_delegate connectResult:BuzzBTFail withError:error];

    }

}

 

// 丢失连接

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {

    NSString *msg = [NSString stringWithFormat:@"-didDisconnectPeripheral-%@",peripheral.name];

    NSLogK(msg);

    activePeripheral = nil;

    if (_delegate && [_delegate respondsToSelector:@selector(disConnectResult:withError:)]) {

        [_delegate disConnectResult:BuzzBTFail withError:error];

    }

}

 

// 服务

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {

    if (error) {

        NSString *msg = [NSString stringWithFormat:@"did discover peripheral:%@(%@) service error : %@", peripheral.name, peripheral.identifier, error.localizedDescription];

        NSLogK(msg);

        return;

    }

    NSString *msg = [NSString stringWithFormat:@"did discover peripheral:%@(%@) service %@", peripheral.name, peripheral.identifier, peripheral.services];

    NSLogK(msg);

    //,[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]

    for (CBService *service in peripheral.services) {

        if ([service.UUID.UUIDString isEqualToString:UUID_CONTROL_SERVICE]) {

           [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]] forService:service];

                break;

        }

 

    }

}

 

// periperal discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {

    if (error) {

        NSString *msg = [NSString stringWithFormat:@"peripheral %@(%@) did discover characteristic error %@", peripheral.name, peripheral.identifier, error.localizedDescription];

        NSLogK(msg);

        return;

    }

    

    NSString *msg = [NSString stringWithFormat:@"peripheral %@(%@) did discover characteristics %@", peripheral.name, peripheral.identifier, service.characteristics];

    NSLogK(msg);

    for (CBCharacteristic *chara in service.characteristics) {

        if ([chara.UUID isEqual:[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]]) {

            [peripheral setNotifyValue:YES forCharacteristic:chara];

            controlCharacteristic = chara;

        }

 

    }

 

}

 

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    NSData *data = characteristic.value;

    NSString *response = [self dataToHex:data];

    NSString *msg = [NSString stringWithFormat:@"command did get response:%@", response];

    NSLogK(msg);

  

}

 

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

//    NSString *msg = [NSString stringWithFormat:@"didWriteValueForCharacteristic:%@", error];

//    TDLogK(msg);

    

    TDLog(@"error is %@",error);

    TDLog(@"characteristic is %@",characteristic);

    

}

 

#pragma mark 发送和接收数据解析相关,以下是针对我目前项目中蓝牙功能的封装,不一定适用其他项目

- (NSData *)command:(NSString *)hexCommand withOption:(NSString *)option{

    

    NSData *optionData = [option dataUsingEncoding:NSUTF8StringEncoding];

    

    NSInteger totalLength = optionData.length + 5;

    

    NSString *hexOptionString = [self dataToHex:optionData];

    

    NSString *lengthString = [NSString stringWithFormat:@"%X",(int)totalLength];

    

    //最长只支持 255 长度的命令

    if (lengthString.length==1) {

        lengthString = [NSString stringWithFormat:@"0%@",lengthString];

    }

    

    NSString *hexCommandString = [NSString stringWithFormat:hexCommand,lengthString,hexOptionString];

    

    NSData *commandData = [self dataFromHexString:hexCommandString];

    

    return commandData;

}

 

- (NSData *)dataFromHexString:(NSString *)hexString {

    const char *chars = [hexString UTF8String];

    long i = 0, len = hexString.length;

    

    NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];

    char byteChars[3] = {'\0','\0','\0'};

    unsigned long wholeByte;

    

    while (i < len) {

        byteChars[0] = chars[i++];

        byteChars[1] = chars[i++];

        wholeByte = strtoul(byteChars, NULL, 16);

        [data appendBytes:&wholeByte length:1];

    }

    

    return data;

}

 

- (NSString *)dataToHex:(NSData *)data {

    NSUInteger i, len;

    unsigned char *buf, *bytes;

    

    len = data.length;

    bytes = (unsigned char*)data.bytes;

    buf = malloc(len*2);

    

    for (i=0; i<len; i++) {

        buf[i*2] = itoh((bytes[i] >> 4) & 0xF);

        buf[i*2+1] = itoh(bytes[i] & 0xF);

    }

    

    return [[NSString alloc] initWithBytesNoCopy:buf

                                          length:len*2

                                        encoding:NSUTF8StringEncoding

                                    freeWhenDone:YES];

}

 

static inline char itoh(int i) {

    if (i > 9) 

        return 'A' + (i - 10);

    return '0' + i;

}

 

 

/*

 *   把返回命令里的传递值拿出来

 */

- (NSString *)valueStringWithResponse:(NSData *)data {

    //NSData *ad = [NSData dataWithBytes:0x00 length:2];

    if (data.length <= 5) {

        return nil;

    }

    NSData *tailData = [data subdataWithRange:NSMakeRange(data.length-1, 1)];

    if ([tailData isEqualToData:[NSData dataWithBytes:"\0" length:1]]) {

        if (data.length > 6) {

            NSData *valueData = [data subdataWithRange:NSMakeRange(4, data.length-5)];

            NSString *valueString = [[NSString alloc] initWithData:valueData encoding:NSUTF8StringEncoding];

            return valueString;

        }

    } else {

        if (data.length > 5) {

            NSData *valueData = [data subdataWithRange:NSMakeRange(4, data.length-4)];

            NSString *valueString = [[NSString alloc] initWithData:valueData encoding:NSUTF8StringEncoding];

            return valueString;

        }

    }

    return nil;

}

 

@end

 //定义日志类

//

//  kbConsoleLog.h

//  TestDemoForKB

//

//  Created by lollipop on 2017/4/1.

//  Copyright © 2017年 lollipop. All rights reserved.

//

 

#import <UIKit/UIKit.h>

 

@interface kbConsoleLog : NSObject

 

+ (instancetype)sharedInstance;

 

- (void)showLog:(NSString *)log;

 

@end

 //.m文件

//

//  kbConsoleLog.m

//  TestDemoForKB

//

//  Created by lollipop on 2017/4/1.

//  Copyright © 2017年 lollipop. All rights reserved.

//

 

#import "kbConsoleLog.h"

 

@interface kbConsoleLog()

 

@property (nonatomic,copy)      UIWindow    *mainWindow;

 

@property (nonatomic,strong)    UITextView  *logView;

 

@end

 

@implementation kbConsoleLog

 

static kbConsoleLog *_consoleManager;

 

+ (instancetype)allocWithZone:(struct _NSZone *)zone {

    static dispatch_once_t onceToken;

    

    dispatch_once(&onceToken, ^{

        _consoleManager = [super allocWithZone:zone];

    });

    

    return _consoleManager;

}

 

- (nonnull id)copyWithZone:(nullable NSZone *)zone {

    return _consoleManager;

}

 

+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _consoleManager = [[self alloc] init];

    });

    

    return _consoleManager;

}

 

- (void)showLog:(NSString *)log {

    if ([NSThread isMainThread]) {

//        [self show:log];

    } else {

        dispatch_async(dispatch_get_main_queue(), ^{

//            [self show:log];

        });

    }

}

 

- (void)show:(NSString *)log {

    [self initMainWindow];

    // 打印到控制台中

    TDLog(@"%@", log);

    

    NSMutableString *string = [_logView.text mutableCopy];

    [string appendFormat:@"\n %@",log];

    _logView.text = string;

    

    NSRange bottom = NSMakeRange(string.length - 1, 1);

    [_logView scrollRangeToVisible:bottom];

}

 

- (void)initMainWindow {

    if (_mainWindow) {

        return;

    }

    _mainWindow = [[UIWindow alloc] init];

    _mainWindow.rootViewController = [UIViewController new];

    _mainWindow.windowLevel = UIWindowLevelAlert;

    _mainWindow.userInteractionEnabled = NO;

    CGFloat rgbF = 30.0 / 255;

    _mainWindow.backgroundColor = [UIColor colorWithRed:rgbF green:rgbF blue:rgbF alpha:0.1];

    _mainWindow.frame = [UIScreen mainScreen].bounds;

    _logView = [[UITextView alloc] init];

    _logView.frame = _mainWindow.bounds;

    _logView.textColor = [UIColor blackColor];

    _logView.backgroundColor = [UIColor clearColor];

    _logView.text = @"0-----";

    [_mainWindow addSubview:_logView];

    _mainWindow.hidden = NO;

    [_mainWindow makeKeyWindow];

}

@end

 

//当前使用蓝牙

-(void)CONNECT{

    

    [LSBuzzBTmanager sharedInstance].delegate = self;

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        

        [[LSBuzzBTmanager sharedInstance] FinddevFiter:YES];

    });

}

/*

 * @descripe 当前蓝牙是否可用

 * @param available 当前蓝牙是否可用

 */

- (void)centralManagerDidUpdateState:(BOOL)available {

    TDLog(@"--centralManagerDidUpdateState--");

    

}

/*

 * @descripe 搜到蓝牙设备的回调,每次搜到一个新设备都会回调

 * @param isFinish 搜索是否结束

 * @param list 搜索当前搜索结果

 * @param error 参考BuzzError

 */

-(void)fetchDevice:(BOOL)isFinish device:(NSArray *)list apack:(NSArray *)adpacklist withResult:(BuzzResult)error{

    self.devList = list;

    self.adpackList=adpacklist;

    TDLog(@"self.adpackList is %@",self.adpackList);

    [self.tableView reloadData];

}

 

/*

 * @descripe 连接制定蓝牙设备结果的回调

 * @param error 参考BuzzError

 */

- (void)connectResult:(BuzzResult)result withError:(NSError *)error {

    if (result == BuzzBTSuccess) {

        [self performSegueWithIdentifier:@"pushToDetail" sender:nil];

    }

    TDLog(@"error is %@",error);

}

 

/*

 * @descripe 连接被断开,被动断开或者主动断开

 * @param error 参考BuzzError

 */

- (void)disConnectResult:(BuzzResult)result withError:(NSError *)error {

    TDLog(@"error is %@",error);

    

    [SVProgressHUD dismiss];

    [HintView hintViewWithMessage:error.localizedDescription];

 

//    [self initycdata:self.currentmodels];

    //远程开门

}

-(void)hasconnectResult:(BuzzResult)result withError:(NSError *)error{

 

    

    __block RemoteOpenDoorViewController *weakSelf = self;

    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC));

    dispatch_after(delayTime, dispatch_get_main_queue(), ^{

        [weakSelf delayMethod];

    });

    

    

 

    NSTimer *timer = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(timerAction) userInfo:nil repeats:NO];

    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

    [timer invalidate];

}

-(void)delayMethod{

    [SVProgressHUD dismiss];

    [[LSBuzzBTmanager sharedInstance] writeValue:self.currentmacs option:nil];

}

-(void)timerAction{

    [[LSBuzzBTmanager sharedInstance] stopSearchDevice];

    for (int i=0; i<self.devList.count; i++) {

        CBPeripheral *per=self.devList[i];

      [[LSBuzzBTmanager sharedInstance] disconnectBuzzard:per];

    }

}

//开门

    [[LSBuzzBTmanager sharedInstance] connectBuzzard:per];//后台直接操作

posted @ 2019-01-09 16:16  倾城孤月  阅读(319)  评论(0)    收藏  举报