We are IoTalabs and we are a group of Internet of Things enthusiasts that love hacking together different devices. We've been working on many projects.
Check out our current project http://doteverything.co/
We wanted to share our experience in connecting to bluetooth devices using Apple's CoreBluetooth framework!
You will need your own peripheral to test out the code that we walk through in this guide. The guide will assume that the reader is already familiar with the fundamentals of Objective C/Object Oriented Programming. CoreBluetooth is not too complicated, once you realize that it is essentially a chain of callback functions. Let's get started!
Step 1: Overview of Conepts
The CoreBluetooth framework allows us to make use of several different objects organized into a hierarchy, shown above.
CBPeripheral: represents remote peripheral devices that your app is able to connect to
CBService: a collection of data and associated behaviors for accomplishing a function or feature of a device (essentially a group of characteristics). A peripheral can have multiple services.
CBCharacteristic: contains a single value and any number of descriptors describing that value. The characteristic we use in this tutorial is the transmission characteristic, which allows us to send messages to the Dot.
Callback: functions that trigger once an action has been successfully performed
Step 2: Setup
First, open Xcode and create a new project. When prompted, select single-view application, Objective-C as the language, and iPhone as the device. Once you have created your project, open the header file (ViewController.h) and import CoreBluetooth as shown above.
After the class declaration, include the necessary protocols between the brackets <>, shown above.
Within the interface tags, include the following strong references as properties:
@property CBCentralManager *myManager;
@property CBPeripheral *myDot;
We will be using these properties in the implementation of the program.
Step 3: CentralManager and Delegate Methods
When the program loads, we want to instantiate the CentralManager object and begin the chain of callbacks mentioned earlier. When instantiating the CentralManager object, make sure that we have "self" as the chosen delegate parameter. This will allow the CentralManager callback methods within the ViewController to be used.
When we first instantiate a CentralManager object, it is not yet powered on. That is why we make use of the didUpdateState callback. Once the manager powers on, the switch will tell the manager to begin searching for our peripherals (in this case our Dot)! Other possible states are included in the switch for illustrative purposes.
Step 4: Central Manager Delegate Methods
The rest of the delegate methods for the manager are shown above. Every disoverable peripheral will trigger the didDiscoverPeripheral method, so we filtered peripherals we wanted to connect with using a string comparator and peripheral names. Since the particular peripheral we are looking for is named "DOT", we included an if statement checking whether or not we should connect. We assign the peripheral named "DOT",as our property in case we need to access it later, and the property creates a strong reference allowing us to do this.
All peripherals have names, so you may want to check what yours are if you are not sure. Do this by logging peripheral names to the console as they are discovered in the didDiscoverPeripheral method.
We set the peripheral delegate property to self. This will allow the peripheral callback methods within the ViewController to be used.
Once we have successfully connected to the peripheral, we are interested in discovering its services. Services contain characteristics, which is what we are interested in accessing and changing. In our example, we will later be looking for the transmission characteristic so that we can send a signal to the Dot telling it to turn on.
Step 5: Peripheral Callback Methods
Once we have discovered the services, which we began in the previous step, we can search for the service we are looking for. With our hardware, the service we are searching for has the UUID shown above. CBObjects have their own UUIDs, which allow us to identify which services/characteristics/peripherals we are looking for. We iterate through the services to search for the one we want. In this case, the service we are looking for has the UUID shown above. Yours may be different, so check your hardware specs. With the correct service identified, it is time to discover its characteristics.
We undergo a similar process for characteristics, and iterate through their service's characteristics until we find the desired transmission characteristic. It is important to subscribe to the characteristic using the peripheral's setNotify methods. This will allow us to know when the values of the characteristic have changed, which will be relevant to the advanced tutorial.
Lastly, we encode a message into NSData so that it can be sent to the peripheral. In this case, we are encoding a command to turn the Dot's light on!
Step 6: Await Results
Your peripheral should have received the message! In our case, the Dot's light has turned on, indicating that the string was received. Thanks for reading, and please don't hesitate to ask any questions!