View All Posts
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi

We’ve just finished the first iOSCon hackathon. Some great work was done with the Affectiva emotion SDK along with some great stuff with Estimotes and Scentees.

I played with my Raspberry Pi and turned it into a fully functional bluetooth device communicating with an app running on my iPhone. I also plugged in the Scentee SDK and got the phone making a smell when the Pi picked up key presses on the remote control. I really wanted the Pi to make the smells, but the volume from the Pi’s audio jack wasn’t loud enough to activate the device.

To get my raspberry pi communicating I installed node and then used Bleno.

Bleno is a really nice node.js module for implementing Bluetooth low energy peripherals. For example to get an iBeacon running you just need the following code:

var bleno = require('bleno');
var uuid = 'e2c56db5dffb48d2b060d0f5a71096e0';
var major = 0; // 0x0000 - 0xffff
var minor = 0; // 0x0000 - 0xffff
var measuredPower = -59; // -128 - 127

bleno.startAdvertisingIBeacon(uuid, major, minor, measuredPower);

Assuming you’ve saved this file to ibeacon.js you can run it using:

$ sudo node ibeacon.js

To create a more fully functional device than a simple iBeacon we need to do a bit more work. I wanted to fully exercise my Raspberry Pi, using all the sensors that I’d wired up so far, connected up with my iPhone. This meant that I’d need to be able to write strings to my LCD display, get a stream of temperature readings and also get notified when an IR remote control button was pushed.

The basic outline of a bluetooth device looks like this using bleno:

var bleno = require('bleno');

bleno.on('stateChange', function(state) {
    console.log('on -> stateChange: ' + state);
    if (state === 'poweredOn') {
    } else {

bleno.on('advertisingStart', function(error) {
    console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
    if (!error) {
            new bleno.PrimaryService({
                uuid : 'b1a6752152eb4d36e13e357d7c225465',
                characteristics : [
                	// add characteristics here

We can now add some characteristics to our service.

For my lcd characteristic I created this:

var data = new Buffer('Send me some data to display');

// new characteristic added to the service
new bleno.Characteristic({
	uuid : '9e739ec2b3a24af0c4dc14f059a8a62d',
	properties : ['read','writeWithoutResponse'],
	onReadRequest : function(offset, callback) {
		if(offset > data.length) {
		} else {
			callback(bleno.Characteristic.RESULT_SUCCESS, data.slice(offset));
	onWriteRequest : function(newData, offset, withoutResponse, callback) {
		if(offset > 0) {
		} else {
			exec('sudo ./lcd "'+newData.toString('utf8')+'"');
			data = newData;

This characteristic provides a read function and a write function. The write function shells out to a simple command line program that sets the contents of the LCD. The read function lets you read back whatever it is you stored.

#include <stdio.h>
#include <wiringPi.h>
#include <mcp23s17.h>
#include <lcd.h>

// BASE port for the SPI GPIO extension
#define BASE    100

int main (int argc, char *argv[])
	printf("Will set text to %s", argv[1]);
	wiringPiSetup () ;
	// initialise the SPI extension
	mcp23s17Setup (BASE, 0, 0) ;
	// setup the LCD
	int fd = lcdInit(2, 16, 4, BASE + 10, BASE + 11, BASE + 12, 
					BASE + 13, BASE + 14, BASE + 15, 0, 0, 0, 0);
	// print whatever is in argv[1]
	lcdClear (fd);
	lcdHome (fd);
	lcdPrintf(fd, argv[1]);

For my InfraRed receiver characteristic I wanted to be able to notify a connected client that there was a new value. To do this we use the onSubscribe event coupled with the node module infrared. The infrared module gives us a nice wrapper around lirc.

var IRW = require('infrared').irw;

new bleno.Characteristic({
	uuid : 'b747cdd0ddcc11e38b680800200c9a66',
	properties : ['notify'],
	onSubscribe : function(maxValueSize, updateValueCallback) {
		irw.on('stdout', function(data) {
			updateValueCallback(new Buffer(data.split(' ')[2]));

When someone subscribes to this property we start up irw and whenever it gets an event we send the button push back to the client.

We should probably also handle the onUnsubscribe event as well and stop irw.

For the temperature sensor we can use the ds18b20 module - there are several other modules that we could use, but this is the first one I found.

new bleno.Characteristic({
	uuid : '4b842c60ddd611e38b680800200c9a66',
	properties : ['notify'],
	onSubscribe : function(maxValueSize, updateValueCallback) {
		setInterval(function() {
			sense.temperature('28-0000057cc14e', function(err, value) {
				updateValueCallback(new Buffer(value + 'C'));
		}, 1000);

When someone subscribes I kick off a repeating timer to read the temperature and send it back every second. Once again, we should really handle the unsubscribe event and kill our timer.

To run the server we do the following:

# load up the SPI driver
$ gpio load spi
#load up the temperature sensors
$ sudo modprobe w1_gpio
$ sudo modprobe w1_therm
# start up the server
$ sudo node server.js

That’s it for the Raspberry Pi side of things - if you have any other sensors or outputs you want to wire up then you can follow a similar pattern.

You can now test your device using one of the many bluetooth test applications that are on the app store or download the (source code)[] and run one yourself.

To build our own app we need to use the Core Bluetooth framework to access our peripheral.

// create the CBCentral manager
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];

// when it is powered on start looking for our peripheral
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
        CBUUID *serviceUUID = [CBUUID UUIDWithString:@"b1a67521-52eb-4d36-e13e-357d7c225465"];
        [central scanForPeripheralsWithServices:@[serviceUUID] options:nil];

// central manager discovered a peripheral
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    self.peripheral = peripheral;
    [self.centralManager stopScan];
    self.peripheral.delegate = self;
    // make a connection to the peripheral
    [self.centralManager connectPeripheral:self.peripheral options:nil];

// connected, start discovering services
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    if(peripheral.state == CBPeripheralStateConnected) {
        [peripheral discoverServices:nil];

// services discovered - find their characteristics
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    for (CBService *service in {
        [peripheral discoverCharacteristics:nil forService:service];

// discovered some characteristics
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    for (CBCharacteristic *characteristic in service.characteristics) {
        if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"9e739ec2-b3a2-4af0-c4dc-14f059a8a62d"]]) {
        	self.lcdCharacteristic = characteristic;
	    if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"b747cdd0-ddcc-11e3-8b68-0800200c9a66"]]) {
            self.irCharacteristic = characteristic;
	    if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"4b842c60-ddd6-11e3-8b68-0800200c9a66"]]) {
            self.tempCharacteristic = characteristic;
        [peripheral readValueForCharacteristic:characteristic];
        [peripheral setNotifyValue:YES forCharacteristic:characteristic];

// this is called in response to the readValueForCharacteristic and also when the peripheral notifies us of changes
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
	// get the value
    NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    // see which characteristic was updated
    if(characteristic == self.lcdCharacteristic) {
        // LCD display
    if(characteristic == self.irCharacteristic) {
        // InfraRed remote
    if(characteristic == self.tempCharacteristic) {
        // Temperature

The first step is to create the core bluetooth central manager. We have to wait for it to power on and then we can start scanning for peripherals.

Once we’ve discovered the peripheral we can connect to it and discover the services it offers and once we find the services we can ask the service what characteristics it supports.

When we get the set of characteristics for the service we can read the current value and we can also subscribe to changes in the value.

When we read values or are notified of values we get a call to didUpdateValueForCharacteristic.

To write values to our new LCD characteristic we call:

    [self.peripheral writeValue:[text dataUsingEncoding:NSUTF8StringEncoding]

That’s it! Bleno provides a really nice environment for wiring up bluetooth services and the Core Bluetooth frameworks makes it very easy to connect up to your device.


Related Posts

Raspberry Pi iBeacon - In today's blog post, I successfully turned my Raspberry Pi into an iBeacon using a Bluetooth dongle and following an Adafruit tutorial. I had to go under the hood a bit to make sure my dongle was recognized, but after adding some udev rules, it was good to go. Then, with a string of terminal commands, I was able to set it up as an iBeacon broadcasting a specific UUID. Testing it out with a basic iOS app, I was able to detect the signal strength from the beacon! While it wasn't the flashiest project, it was definitely satisfying to see it work.
Raspberry pi Infrared Receiver - In this fun tech adventure, I successfully managed to sync my infrared receiver to my Raspberry Pi. This involved correctly wiring up my IR sensor, installing and setting up LIRC, and creating a new lirc config file. I explained each step in detail and shared my major milestones, which included seeing a list of pulses when the remote was pointed at the receiver. Now my Raspberry Pi is fully controlled by my remote.
GameKit and GameCenter - Had a blast at iOSDevUK - a fantastic conference that was not only filled with intriguing talks, but also offered me the opportunity to present my own talk. I discussed making real time multiplayer games using GameKit and GameCenter. The slides and notes from my talk are available for download if you're interested!
Forget SSH and vim, Use VSCode to Remote Develop on the Raspberry Pi - In this blog post, I share how you can avoid hassles of SSH and use VSCode for remotely developing on the Raspberry Pi. I walk through how to initially configure the Pi in a headless setup using the Pi imager app. Then, we install the 'Remote Development' extension in VSCode. I illustrate how easy it is to connect to the Pi using our SSH credentials, clone a GitHub project, and install python extensions. Finally, I explore how to run the code and debug it. However, note that the method doesn't support armv6, so you can't use it on Pi Zero.
Raspberry Pi temperature sensor - In just a bit of time, I managed to successfully get my temperature sensor, the DS18B20, up and running on my new Raspberry Pi. My starter kit even included a ready made circuit board for the sensor, making wiring a no-brainer. After following the setup instructions and inputting a few commands, voilà, my temperature readouts were coming in loud and clear. Ready to tinker around and perhaps even move the connection pin if needed.

Related Videos

WiFi or BlueTooth - What's the best way to communicate with our things? - Discover the world of smart devices and the wireless connection options available for app developers, such as Bluetooth Low Energy and Wi-Fi. Learn about the history, performance, and challenges of these technologies and how to use them to build successful apps that communicate with hardware.
Reviving a Broken iPad: Transforming it into a Magic Mirror with Raspberry Pi Zero - Learn how to transform an old iPad 1 screen and a Raspberry Pi Zero into a Magic Mirror with this step-by-step guide! Enhance your home with this unique, DIY upgrade.
Getting started with Raspberry Pi Pico - MicroPython - Learn how to get started with Raspberry Pi Pico by soldering headers, writing codes, and building a classic blinking LED project in this tutorial.
AI-Powered Coding: GitHub Copilot Writes Arduino Blink Sketch & WiFi Setup - Find out how GitHub Co-Pilot's AI impressively handles a blink sketch and Wi-Fi setup in an Arduino project!
Pong on the apple watch - Get a glimpse of a quick demo on playing Pong on the Apple Watch, skillfully hacked together at the iOSDevUK event! Don't miss out!
HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
Blog Logo

Chris Greening


> Image


A collection of slightly mad projects, instructive/educational videos, and generally interesting stuff. Building projects around the Arduino and ESP32 platforms - we'll be exploring AI, Computer Vision, Audio, 3D Printing - it may get a bit eclectic...

View All Posts