Shuichi Tsutsumi: Practical Core Bluetooth in IoT & Wearable projects

1fa9cb8c7997c8c4d3d251fb5e41f749?s=47 Realm
June 16, 2016

Shuichi Tsutsumi: Practical Core Bluetooth in IoT & Wearable projects

In recent years, "IoT" or "Wearable" are one of buzzwords, so you might have interests in building hardware products. But learning how to develop electric circuits, mechanical systems or embedded systems etc. from zero is so difficult.

However, iOS developers can contribute to projects of hardware products with the knowledge of Core Bluetooth / Bluetooth Low Energy (BLE), even if they are not familiar with hardware layer.

In this session, you can learn the basics of Core Bluetooth / BLE (what it is, why we use it, and how it works), and practical knowledges to build apps for hardware products (how to design the apps, how to test without actual hardware prototypes, troubleshooting tips, and how the apps can be reviewed by Apple) which I learned through actual IoT/Wearable projects.

This would be interesting & understandable even if you are not familiar with or have no interests in Core Bluetooth because of the actual examples.

Bio: Shuichi is an iOS Freelancer who has developed many IoT related apps using Bluetooth Low Energy. He co-authored "iOS x BLE Core Bluetooth Programming" (2015) and authored "iOS Programming - Advanced 100 Recipes" (2013). He is the owner of popular OSS repositories such as iOS-9-Sampler, AnimatedTransitionGallery, and many more, ultimately totaling 15,000 stars.
Twitter: https://twitter.com/shu223

1fa9cb8c7997c8c4d3d251fb5e41f749?s=128

Realm

June 16, 2016
Tweet

Transcript

  1. 2.
  2. 3.
  3. 4.
  4. 6.
  5. 16.
  6. 17.

    • Low energy • NOT compatible with Classic BT •

    Uses 2.4 GHz radio frequencies • Marketed by the Bluetooth SIG
  7. 18.

    • Low energy • NOT compatible with Classic BT •

    Uses 2.4 GHz radio frequencies • Marketed by the Bluetooth SIG • etc…
  8. 19.

    • Low energy • NOT compatible with Classic BT •

    Uses 2.4 GHz radio frequencies • Marketed by the Bluetooth SIG • etc…
  9. 22.

    The API ‘Core Bluetooth’ is open for developers • API

    for Classic BT is NOT open. - Requires MFi certification.
  10. 23.

    BLE is almost the ONLY way to enable iOS apps

    to communicate with external hardware without infrastructure or MFi.
  11. 25.
  12. 30.

    Moff Band Moff App Sensor Data BLE Connection Sensors -

    Gyroscope - Accelerometer Analyze sensor data
  13. 31.

    Moff Band Moff App Sensor Data BLE Connection Sensors -

    Gyroscope - Accelerometer Analyze sensor data Recognize - Gesture - Posture
  14. 32.

    Moff Band Moff App Sensor Data BLE Connection Sensors -

    Gyroscope - Accelerometer Analyze sensor data Recognize - Gesture - Posture Play sounds
  15. 39.

    Scan Step 1. Scan Advertise : Search for nearby BLE

    devices centralManager.scanForPeripheralsWithServices(nil, options: nil)
  16. 41.

    Scan Step 1. Scan Advertise Discover : Search for nearby

    BLE devices func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber!) { print(“Discovered a BLE device!”) }
  17. 42.

    Scan Step 1. Scan Advertise Discover : Search for nearby

    BLE devices func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber!) { print(“Discovered a BLE device!”) } Central
  18. 43.

    Scan Step 1. Scan Advertise Discover : Search for nearby

    BLE devices func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber!) { print(“Discovered a BLE device!”) } Peripheral Central
  19. 51.

    Moff Service xx Service Step 3. Subscribe: Ready to receive

    data GATT = Generic Attribute Profile
  20. 52.

    Moff Service xx Service Button Characteristic xx Characteristic Sensor Characteristic

    Step 3. Subscribe: Ready to receive data GATT = Generic Attribute Profile
  21. 53.

    Moff Service xx Service Button Characteristic xx Characteristic Sensor Characteristic

    Subscribe (Request to be notified) Step 3. Subscribe: Ready to receive data GATT = Generic Attribute Profile
  22. 54.

    Moff Service xx Service Button Characteristic xx Characteristic Sensor Characteristic

    Subscribe (Request to be notified) Step 3. Subscribe: Ready to receive data GATT = Generic Attribute Profile peripheral.setNotifyValue(true, forCharacteristic: c)
  23. 58.

    Step 4. Notify Notify subscribers Moff Service Sensor Characteristic xxxx

    Characteristic Update the value func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) { print(“Received sensor data!”) }
  24. 59.

    Step 4. Notify Notify subscribers Moff Service Sensor Characteristic xxxx

    Characteristic Update the value func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) { print(“Received sensor data!”) }
  25. 62.

    BLE

  26. 73.
  27. 77.

    Group conversation system with VoIP - Detects the human voice

    - Cuts out all background noise → Can be used even in areas with poor coverage!
  28. 91.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  29. 92.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  30. 93.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  31. 94.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  32. 95.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  33. 96.

    GATT to send sensor data Foo Service Sensor Data Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Bar Service xx Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: acc x, acc y, acc z, gyro x, gyro y, gyro z (2bytes for each) xx Characteristic
  34. 97.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00
  35. 98.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00
  36. 99.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00
  37. 100.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00 Button interactions
  38. 101.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00 Button interactions
  39. 102.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00 Button interactions
  40. 103.

    GATT to send button interactions Foo Service Button Control Characteristic

    UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Notify Value: 0x01 or 0x00 Button interactions Y1VTIFE Y3FMFBTFE
  41. 104.

    GATT for remote control Foo Service Remote Control Characteristic UUID:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Write Value: Horizontal (-100 ~ 100), Vertical (-100 ~ 100)
  42. 105.

    GATT for remote control Foo Service Remote Control Characteristic UUID:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Write Value: Horizontal (-100 ~ 100), Vertical (-100 ~ 100)
  43. 106.

    GATT for remote control Foo Service Remote Control Characteristic UUID:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Write Value: Horizontal (-100 ~ 100), Vertical (-100 ~ 100) values
  44. 107.

    GATT for remote control Foo Service Remote Control Characteristic UUID:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Write Value: Horizontal (-100 ~ 100), Vertical (-100 ~ 100) values
  45. 108.

    GATT for remote control Foo Service Remote Control Characteristic UUID:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Properties: Write Value: Horizontal (-100 ~ 100), Vertical (-100 ~ 100) values
  46. 112.

    GATT for generic commands Electronic Stimulation Control Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Properties: Write Value: 1 byte 4 Commands: - Change the pulse frequency - Change the electric current - Right channels on/off - Left channels on/off
  47. 113.

    GATT for generic commands Electronic Stimulation Control Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Properties: Write Value: 1 byte 4 Commands: - Change the pulse frequency - Change the electric current - Right channels on/off - Left channels on/off
  48. 114.

    GATT for generic commands Electronic Stimulation Control Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Properties: Write Value: 1 byte High-order 2 bits - 00: Change the pulse frequency - 01: Change the electric current - 10: Left channels on/off - 11: Right channels on/off
  49. 115.

    GATT for generic commands Electronic Stimulation Control Characteristic UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Properties: Write Value: 1 byte High-order 2 bits - 00: Change the pulse frequency - 01: Change the electric current - 10: Left channels on/off - 11: Right channels on/off
  50. 118.

    How to define GATT 1. Create UUID for the service

    & characteristic $ uuidgen CEEA31BC-BEAC-4A78-B7ED-FC96B6254D4C
  51. 119.

    How to define GATT 1. Create UUID for the service

    & characteristic 2. Define the properties (Read, Notify, Write, etc.) $ uuidgen CEEA31BC-BEAC-4A78-B7ED-FC96B6254D4C
  52. 120.

    How to define GATT 1. Create UUID for the service

    & characteristic 2. Define the properties (Read, Notify, Write, etc.) Peripheral → Central: Notify 
 Central → Peripheral: Write $ uuidgen CEEA31BC-BEAC-4A78-B7ED-FC96B6254D4C
  53. 121.

    How to define GATT 1. Create UUID for the service

    & characteristic 2. Define the properties (Read, Notify, Write, etc.) Peripheral → Central: Notify 
 Central → Peripheral: Write 3. Define the value format $ uuidgen CEEA31BC-BEAC-4A78-B7ED-FC96B6254D4C
  54. 122.

    How to define GATT 1. Create UUID for the service

    & characteristic 2. Define the properties (Read, Notify, Write, etc.) Peripheral → Central: Notify 
 Central → Peripheral: Write 3. Define the value format Usually limited to 20 bytes $ uuidgen CEEA31BC-BEAC-4A78-B7ED-FC96B6254D4C
  55. 125.

    Background behaviors on iOS • Very limited - Listening to

    music - Getting location data - Downloading data
  56. 126.
  57. 128.
  58. 129.

    You would have to always keep the app in the

    foreground, while snowboarding!
  59. 130.
  60. 134.

    What functions can be used in the background? • Scanning

    peripherals • Connecting with peripherals
  61. 135.

    What functions can be used in the background? • Scanning

    peripherals • Connecting with peripherals • Reading characteristics’ value
  62. 136.

    What functions can be used in the background? • Scanning

    peripherals • Connecting with peripherals • Reading characteristics’ value • Writing characteristics’ value
  63. 137.

    What functions can be used in the background? • Scanning

    peripherals • Connecting with peripherals • Reading characteristics’ value • Writing characteristics’ value • Receiving notifications
  64. 138.

    What functions can be used in the background? • Scanning

    peripherals • Connecting with peripherals • Reading characteristics’ value • Writing characteristics’ value • Receiving notifications Almost all functions can be used even in the background!
  65. 140.
  66. 145.

    Limitations • Longer intervals for scanning • Must explicitly specify

    one or more services to scan • CBCentralManagerOptionShowPowerAlertKey option is ignored
  67. 146.

    Limitations • Longer intervals for scanning • Must explicitly specify

    one or more services to scan • CBCentralManagerOptionShowPowerAlertKey option is ignored Resources - Core Bluetooth Programming Guide - Core Bluetooth Framework Reference (also in headers)
  68. 148.
  69. 150.
  70. 151.

    State Preservation and Restoration The system takes over the BLE

    tasks even after the app is killed. - Preserves the state of the app’s central managers and continues the BLE tasks on their behalf.
  71. 152.

    State Preservation and Restoration The system takes over the BLE

    tasks even after the app is killed. - Preserves the state of the app’s central managers and continues the BLE tasks on their behalf. - Relaunches the app into the background and calls the corresponding delegate method.
  72. 153.

    State Preservation and Restoration The system takes over the BLE

    tasks even after the app is killed. - Preserves the state of the app’s central managers and continues the BLE tasks on their behalf. - Relaunches the app into the background and calls the corresponding delegate method. → The app can handle BLE events!
  73. 154.
  74. 156.

    • The app is killed by the system • The

    user pushes the button on the peripheral device
  75. 157.

    • The app is killed by the system • The

    user pushes the button on the peripheral device • The system receives the notification
  76. 158.

    • The app is killed by the system • The

    user pushes the button on the peripheral device • The system receives the notification • The app is relaunched in the BG and the delegate method is called.
  77. 159.

    func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) { print(“Received

    the characteristic data!”) } • The app is killed by the system • The user pushes the button on the peripheral device • The system receives the notification • The app is relaunched in the BG and the delegate method is called.
  78. 160.

    func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) { print(“Received

    the characteristic data!”) } • The app is killed by the system • The user pushes the button on the peripheral device • The system receives the notification • The app is relaunched in the BG and the delegate method is called. The app can process the button interaction!
  79. 162.

    Implementation • Add an option when initializing the CBCentralManager object.

    let options = [ CBCentralManagerOptionRestoreIdentifierKey: "somekey" ] centralManager = CBCentralManager( delegate: self, queue: queue, options: options)
  80. 163.

    Implementation • Implement the delegate method which is called when

    the app is restored. func centralManager(central: CBCentralManager, willRestoreState dict: [String : AnyObject]) { print("Restored") }
  81. 165.

    Testing the restoration • Kill the app as if it

    was killed by the iOS kill(getpid(), SIGKILL);
  82. 167.

    Did the HW prototypes exist when develop the apps? Projects

    HW prototypes existed? Moff YES WHILL NO BONX NO SmartDrive YES PLEN2 NO Music for the Deaf NO
  83. 173.
  84. 174.
  85. 179.
  86. 182.

    Emulator App • Develop another iOS app as the alternative

    to the peripheral device • Use CBPeripheralManager
  87. 183.

    Emulator App • Develop another iOS app as the alternative

    to the peripheral device • Use CBPeripheralManager • Easier for iOS engineers
  88. 184.
  89. 185.
  90. 186.
  91. 187.

    =

  92. 196.

    • Connection dropped • Can’t discover services or characteristics •

    Fail to write • Incorrect characteristic values
  93. 197.

    • Connection dropped • Can’t discover services or characteristics •

    Fail to write • Incorrect characteristic values • Incorrect behaviors in the background
  94. 198.

    • Connection dropped • Can’t discover services or characteristics •

    Fail to write • Incorrect characteristic values • Incorrect behaviors in the background • etc…
  95. 199.

    Identify which side the problem is on Is the problem

    on the central side or on the peripheral side? → Compare with another iOS app like ‘LightBlue’
  96. 202.

    Can’t find the peripheral • Scanning, but can’t find the

    peripheral device Scan but ‘didDiscover’ method isn’t called
  97. 209.
  98. 216.

    func centralManager( central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String :

    AnyObject], RSSI: NSNumber!) { print(advertisementData) } Filtered by iOS! → Can’t see all of the advertisement data
  99. 217.

    func centralManager( central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String :

    AnyObject], RSSI: NSNumber!) { print(advertisementData) } Filtered by iOS! → Can’t see all of the advertisement data e.g. Can’t see the ‘Manufacture Data’ field of iBeacon
  100. 218.
  101. 221.
  102. 222.
  103. 223.
  104. 228.
  105. 229.
  106. 235.

    Videos for review • Show how the app works with

    the peripheral device • Not need to be cool!
  107. 236.
  108. 239.
  109. 241.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product
  110. 242.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples
  111. 243.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples - Defining GATT
  112. 244.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples - Defining GATT - Defining background behaviors
  113. 245.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples - Defining GATT - Defining background behaviors - Testing without HW prototypes
  114. 246.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples - Defining GATT - Defining background behaviors - Testing without HW prototypes - Troubleshooting
  115. 247.

    Recap • What is Bluetooth Low Energy? • Basics of

    Core Bluetooth with an actual product • Practical Core Bluetooth with specific examples - Defining GATT - Defining background behaviors - Testing without HW prototypes - Troubleshooting - App Review
  116. 250.
  117. 251.
  118. 252.
  119. 253.
  120. 257.

    private let centralManager = CBCentralManager() override func viewDidLoad() { super.viewDidLoad()

    centralManager.delegate = self } private var centralManager: CBCentralManager! override func viewDidLoad() { super.viewDidLoad() centralManager = CBCentralManager(delegate: self, queue: nil) } From To
  121. 258.
  122. 259.

    Thank you! Shuichi Tsutsumi - iOS Freelancer • Twitter: @shu223

    • GitHub: shu223 • Blog: https://medium.com/@shu223/ • Email: shuichi0526@gmail.com