Successfully reported this slideshow.
BLUETOOTH LEを使った、
すれ違い通信
2014.2.25
Bitz Co., Ltd.
•村上幸雄	

•@m_yukio	

•ビッツ有限会社

http://www.bitz.co.jp/

今回のサンプルコードは以下のURL.
https://github.com/murakami/workbook/tree/master/...
Bluetoothは、省電力な電波を使った無線通信
で、最新の4.xでは対応機器は次の3つに分類さ
れます。
分類

Bluetooth Smart

Bluetooth Smart Ready

Bluetooth

説明
4.0で追加された...
iOSでBluetoothに対応する方法を整理してみます。

Bluetoothの種類

説明
MFi機器に対してExternal Accessory
Frameworkで通信。

従来のBLuetooth
Game Kit

Bluetoot...
すれ違い通信

Bluetooth LE

識別子

識別子

識別子を交換
Service
UUID

Central

発見

Peripheral

Advertise

Peripheralが対応しているService UUIDをAdvertiseする。
Centralは探しているService UUIDがないか...
SAMPLE CODE
Central Managerの用意
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self
queue:dispatch_get_global_queue(D...
Peripheralが見つかったので接続する
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral...
キャラクタリスティックUUIDで検索
- (void)peripheral:(CBPeripheral *)peripheral

didDiscoverServices:(NSError *)error

{
if (error) {
[se...
識別子を受け取る
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
...
Peripheral Managerの用意
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
queue:dispatch_get_globa...
識別子の送信
- (void)peripheralManager:(CBPeripheralManager *)peripheral
central:(CBCentral *)central
didSubscribeToCharacterist...
バックグラウンドで動かすには
Info.plistのRequired background modesでApp
communicates using CoreBluetoothを設定。
Info.plistのRequired backgroun...
Core Bluetooth使用時の課題
数分単位の周期でしたバックグラウンドで動かな
いし、動いても数秒。
なので、実際のすれ違い通信は難しい。
iBeaconを試してみる。
CoreBluetoothでビーコンを実装。
CoreLocationでビーコンを検出。
常に検出できるみたい。
iBeaconを探す
/* CLLocationManagerを生成 */
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delega...
検出

領域に入る

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
DBGMSG(@"%s", __func__...
見つけてほしいUUIDを告知

/* CBPeripheralManagerを生成 */
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
q...
iBeacon使用時の課題
個体の識別子はmajorとminorの番号。
ただし、Sample Codeでは取得できていない。
Upcoming SlideShare
Loading in …5
×

Bluetooth LEとiBeaconを使った、すれ違い通信

4,763 views

Published on

第1回 MOSA Tech Meetingの発表資料。

GitHub
https://github.com/murakami/workbook/tree/master/ios/Wibree

Cocoa練習帳
http://www.bitz.co.jp/weblog/

Published in: Technology
  • Be the first to comment

Bluetooth LEとiBeaconを使った、すれ違い通信

  1. 1. BLUETOOTH LEを使った、 すれ違い通信 2014.2.25 Bitz Co., Ltd.
  2. 2. •村上幸雄 •@m_yukio •ビッツ有限会社
 http://www.bitz.co.jp/ 今回のサンプルコードは以下のURL. https://github.com/murakami/workbook/tree/master/ios/Wibree
  3. 3. Bluetoothは、省電力な電波を使った無線通信 で、最新の4.xでは対応機器は次の3つに分類さ れます。 分類 Bluetooth Smart Bluetooth Smart Ready Bluetooth 説明 4.0で追加されたBluetooth Low Energyのみ対 応。 Bluetooth LEと従来のBluetoothの両方に対 応。 従来のBluetoothのみ対応。
  4. 4. iOSでBluetoothに対応する方法を整理してみます。 Bluetoothの種類 説明 MFi機器に対してExternal Accessory Frameworkで通信。 従来のBLuetooth Game Kit Bluetooth LE Core Bluetooth Framework iOSでは、無関係の機器と自由に通信したいのならBluetooth LEという事にな るかと思います。
  5. 5. すれ違い通信 Bluetooth LE 識別子 識別子 識別子を交換
  6. 6. Service UUID Central 発見 Peripheral Advertise Peripheralが対応しているService UUIDをAdvertiseする。 Centralは探しているService UUIDがないか調査する。 Centralが見つけられたら、Peripheralに対して接続要求を出 し、受けいれるとデータ通信が可能になる。 サンプルコードでは、識別子のCharacteristic UUIDを問い合わ せて、識別子を受け取っている。
  7. 7. SAMPLE CODE
  8. 8. Central Managerの用意 self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; Peripheralを探す - (void)centralManagerDidUpdateState:(CBCentralManager *)central { if (central.state != CBCentralManagerStatePoweredOn) { return; } [self scan]; } ! 探すサービスUUID - (void)scan { [self.centralManager scanForPeripheralsWithServices: @[[CBUUID UUIDWithString:WIBREE_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; }
  9. 9. Peripheralが見つかったので接続する - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { if (self.discoveredPeripheral != peripheral) { self.discoveredPeripheral = peripheral; [self.centralManager connectPeripheral:peripheral options:nil]; } } サービスUUIDで検索 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { [self.centralManager stopScan]; [self.data setLength:0]; peripheral.delegate = self; [peripheral discoverServices:@[[CBUUID UUIDWithString:WIBREE_SERVICE_UUID]]]; }
  10. 10. キャラクタリスティックUUIDで検索 - (void)peripheral:(CBPeripheral *)peripheral
 didDiscoverServices:(NSError *)error { if (error) { [self cleanup]; return; } for (CBService *service in peripheral.services) { [peripheral discoverCharacteristics: @[[CBUUID UUIDWithString:WIBREE_CHARACTERISTIC_UUID]] forService:service]; } } ! - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (error) { [self cleanup]; return; } for (CBCharacteristic *characteristic in service.characteristics) { if ([characteristic.UUID isEqual:[CBUUID UUIDWithString: WIBREE_CHARACTERISTIC_UUID]]) { [peripheral setNotifyValue:YES forCharacteristic:characteristic]; } } }
  11. 11. 識別子を受け取る - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; if ([stringFromData isEqualToString:@"EOM"]) { NSString *uniqueIdentifier = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]; dispatch_async(dispatch_get_main_queue(), ^{ [self _notifyParserDidDiscoverUUID:uniqueIdentifier]; }); [peripheral setNotifyValue:NO forCharacteristic:characteristic]; [self.centralManager cancelPeripheralConnection:peripheral]; } [self.data appendData:characteristic.value]; } ! - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:WIBREE_CHARACTERISTIC_UUID]]) { return; } if (! characteristic.isNotifying) { [self.centralManager cancelPeripheralConnection:peripheral]; } }
  12. 12. Peripheral Managerの用意 self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; [self.peripheralManager startAdvertising: 見つけてもらうサービスUUID @{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:WIBREE_SERVICE_UUID]] }]; Peripheralが利用可能 - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { if (peripheral.state != CBPeripheralManagerStatePoweredOn) { return; } self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:WIBREE_CHARACTERISTIC_UUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable]; CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:WIBREE_SERVICE_UUID] primary:YES]; transferService.characteristics = @[self.transferCharacteristic]; [self.peripheralManager addService:transferService]; }
  13. 13. 識別子の送信 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic { self.dataToSend = [[Document sharedDocument].uniqueIdentifier dataUsingEncoding:NSUTF8StringEncoding]; self.sendDataIndex = 0; [self sendData]; } ! - (void)sendData { static BOOL sendingEOM = NO; if (sendingEOM) { BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; if (didSend) sendingEOM = NO; return; } if (self.sendDataIndex >= self.dataToSend.length) return; BOOL didSend = YES; while (didSend) { NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU; NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; if (!didSend) return; NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; self.sendDataIndex += amountToSend; if (self.sendDataIndex >= self.dataToSend.length) { sendingEOM = YES; BOOL eomSent = [self.peripheralManager updateValue: [@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; if (eomSent) sendingEOM = NO; return; } } } ! - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral { [self sendData]; }
  14. 14. バックグラウンドで動かすには Info.plistのRequired background modesでApp communicates using CoreBluetoothを設定。 Info.plistのRequired background modesでApp shares data using CoreBluetoothを設定。
  15. 15. Core Bluetooth使用時の課題 数分単位の周期でしたバックグラウンドで動かな いし、動いても数秒。 なので、実際のすれ違い通信は難しい。
  16. 16. iBeaconを試してみる。 CoreBluetoothでビーコンを実装。 CoreLocationでビーコンを検出。 常に検出できるみたい。
  17. 17. iBeaconを探す /* CLLocationManagerを生成 */ self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; if (! self.locationManager) { /* CLLocationManagerの初期化失敗 */ self.state = kBeaconCentralStateError; self.error = [self _errorWithCode:kBeaconCentralResponseParserGenericError localizedDescription:@"CLLocationManagerの初期化に失敗しました。"]; } return; 探すビーコンのUUID ! /* ビーコン領域を生成 */ NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_SERVICE_UUID]; self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid                 identifier:@"demo.Wibree.BeaconCentralResponseParser"]; if (! self.beaconRegion) { /* ビーコン領域の初期化失敗 */ self.state = kBeaconCentralStateError; self.error = [self _errorWithCode:kBeaconCentralResponseParserGenericError localizedDescription:@"ビーコン領域の初期化に失敗しました。"]; } self.locationManager = nil; return; ! /* ビーコン領域の出入りを監視 */ [self.locationManager startMonitoringForRegion:self.beaconRegion]; ! /* 距離を監視 */ [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
  18. 18. 検出 領域に入る - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { DBGMSG(@"%s", __func__); if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didEnterRegion:)]) { [self.delegate beaconCentralResponseParser:self didEnterRegion:region]; } 領域から外れる } ! - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { DBGMSG(@"%s", __func__); if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didExitRegion:)]) { [self.delegate beaconCentralResponseParser:self didExitRegion:region]; } } 距離を監視 ! -(void)locationManager:(CLLocationManager *)manager
 { } ! didRangeBeacons:(NSArray *)beacons
 inRegion:(CLBeaconRegion *)region DBGMSG(@"%s", __func__); if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didRangeBeacons:inRegion:)]) { [self.delegate beaconCentralResponseParser:self didRangeBeacons:beacons inRegion:region]; } - (void)locationManager:(CLLocationManager *)manager
 monitoringDidFailForRegion:(CLRegion *)region
 withError:(NSError *)error { DBGMSG(@"%s region:%@", __func__, region); DBGMSG(@"%s error:%@", __func__, error); }
  19. 19. 見つけてほしいUUIDを告知 /* CBPeripheralManagerを生成 */ self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; if (! self.peripheralManager) { /* CBPeripheralManagerの初期化失敗 */ self.state = kBeaconPeripheralStateError; self.error = [self _errorWithCode:kBeaconPeripheralResponseParserGenericError localizedDescription:@"CBPeripheralManagerの初期化に失敗しました。"]; return; } ! 見つけてほしいビーコンのUUID /* ビーコン領域を生成 */ NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_SERVICE_UUID]; self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:12345 minor:67890 identifier:@"demo.Wibree.BeaconCentralResponseParser"]; if (! self.beaconRegion) { /* ビーコン領域の初期化失敗 */ self.state = kBeaconPeripheralStateError; self.error = [self _errorWithCode:kBeaconPeripheralResponseParserGenericError localizedDescription:@"ビーコン領域の初期化に失敗しました。"]; self.peripheralManager = nil; return; } ! /* 告知開始 */ NSDictionary *dictionary = [self.beaconRegion peripheralDataWithMeasuredPower:nil]; [self.peripheralManager startAdvertising:dictionary];
  20. 20. iBeacon使用時の課題 個体の識別子はmajorとminorの番号。 ただし、Sample Codeでは取得できていない。

×