codeplanner / TI-CC2650-1

Controlling the Texas Instruments SensorTag (CC2650) from anywhere in the world

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#Controlling TI-CC2650 from anywhere in the world CC2650

by using BLE in combination with full-duplex real-time communication

#About the author Uffe Björklund is one of the founders and CEO of XSockets.NET and have been working with development around real-time communication since 2009.

#Introduction CC2650 from Texas Instruments is an amazing piece of hardware that enables communication over Bluetooth Low Energy (BLE) as a peripheral device to a central unit. The sensortag has a lot of services, and it would be great to be able to access them from anywhere in the world.

##The mission In this post we will take a look at how we can extend the communication with CC2650 by adding a full-duplex communication layer behind the BLE central so that we can read and write in to CC2650 from anywhere in the world. Since this might feel a bit abstract the image below might help to visualize what we are going to do.

There are many ways to connect to a peripheral BLE device, but in this post we will be using a Raspberry Pi 2 as the BLE central device.

Communication

The image illustrates that the CC2650 communicates with the RaspberryPi over BLE. Then the Pi has a TCP/IP connection with XSockets (in this case using nodejs) to be able to send/receive data in full-duplex. XSockets will then be able to send/receive data from any TCP/IP connection so that we can read/write to the CC2650 from anywhere. In the image above the clients is represented by a few selected ones, but it can be anything that has TCP/IP.

IoT & Real-Time Communication

In the world of IoT real-time communication is almost a requirement. The most popular IoT protocols use full-duplex communication, and for a good reason. IoT is often about sending data at a high frequency or receiving data when something happens. Solving this with a request response driven architecture is often a bad idea. With half duplex technique you risk to get a very chatty solution with large overhead and messages that are sent when not needed to.

#Pre-requirements You may be able to use another setup, but this proof of concept is built using the hardware and software specified below.

We will install some additional software later on, but the post assume that you have the things below installed. ##Hardware

#Setting up the Raspberry Pi for BLE We could have built apps for Android/iOS to accomplish the same thing since XSockets.NET has many different clients. However, regardless what client we choose it will still just be a proxy to our final destination. In this case the destination is Azure, but the server can of course be any hosted anywhere.

##Installing required software There are many great resources on how to get started with the Raspberry Pi. One of the best is of course http://www.raspberrypi.org/help/noobs-setup/ . However, that will only get you up and running with the Pi, we also need to install some additional packages to be able to use our Pi as a BLE central device.

If you are not going to setup this on your own Pi you can skip this part. It is only technical details around setting things up.

###Installing Bluez BlueZ provides support for the core Bluetooth layers and protocols, so we need to install bluez and the dependencies to get our BLE adapter working.

####Dependencies Installing the required dependencies.

sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev libbluetooth-dev

####Bluez We need to download, compile and install Bluez.

#####Download

sudo mkdir bluez
cd bluez
sudo wget www.kernel.org/pub/linux/bluetooth/bluez-5.28.tar.xz

#####Unzip, Compile, Install

sudo unxz bluez-5.28.tar.xz
sudo tar xvf bluez-5.28.tar
cd bluez-5.28
sudo ./configure --disable-systemd
sudo make
sudo make install

Now, reboot with the BLE adapter inserted.

##Testing BLE manually When performing read/write to the CC2650 sensortag we will be using a nodejs library called “sensortag” written by Sandeep Mistry. The sensortag library is wrapping another nodejs library for BLE called “noble”, this is also written by Sandeep Mistry

Before we use a library to read/write data we will do this manually to get some basic understanding about BLE in general and CC2650 in specific.

###Make sure BLE is up After the installation of Bluez above we rebooted. Now the BLE adapter should be discovered by our operating system. Now we will make sure that the service is up and running. Navigate to the folder where Bluez was installed (in my case /usr/lib/bluez-5.28/)

Run:

tools/hciconfig

This should show something like

hci0:   Type: BR/EDR  Bus: USB
    BD Address: 00:1A:7D:DA:71:0A  ACL MTU: 310:10  SCO MTU: 64:8
    DOWN
    RX bytes:48436 acl:121 sco:0 events:1615 errors:0
    TX bytes:2371 acl:98 sco:0 commands:84 errors:0

As you can see above the the BLE is DOWN, so to enable it we run.

tools/hciconfig hci0 up

Now, when we run the hcifonfig the BLE will be UP.

root@raspberrypi:/usr/lib/bluez-5.28# tools/hciconfig
hci0:   Type: BR/EDR  Bus: USB
    BD Address: 00:1A:7D:DA:71:0A  ACL MTU: 310:10  SCO MTU: 64:8
    UP RUNNING
    RX bytes:49000 acl:121 sco:0 events:1644 errors:0
    TX bytes:2729 acl:98 sco:0 commands:113 errors:0

###Scan for BLE devices To scan for BLE devices you can use the hcitool.

hcitool lescan

This will continuously provide all devices in range. Make sure that your SensorTag is on!

Example putput

00:12:4B:00:53:11 CC2650 SensorTag

The first part [00:12:4B:00:53:11] is the uuid that we can use to connect to a specific sensortag.

###Connect with GATTTOOL The gatttool (included in Bluez) can help us connect and read/write data to the sensortag. To be able to use the gatttool from anywhere we add it to /usr/local/bin with the command

cp path/to/gatttool /usr/local/bin

Note: On my machine the path/to/gatttool is /usr/lib/bluez-5.28/attrib/gatttool

Now we can connect to the BLE device (sensortag) with the gatttool using the uuid of sensortag.

gatttool -b 00:12:4B:00:53:11 -I

This will return something like

[00:12:4B:00:53:11][LE]>

Then just write "connect"

The complete operation would look like

root@raspberrypi:/# gatttool -b 00:12:4B:00:53:11 -I
[00:12:4B:00:53:11][LE]> connect
Attempting to connect to 00:12:4B:00:53:11
Connection successful
[00:12:4B:00:53:11][LE]>

###Read/Write data In the previous section we used the gatttool to connect to the sensortag. Now lets continue with the gatttool to read and write data to the sensortag. To know what to read and write from the sensortag we need to take a look at the GATT services of the sensortag CC2650. Texas Instruments provides GATT-tables for all services. There is a lot of information, but lets focus on the IR-Temperature service. The table looks like this. enter image description here

By using gatttool we can now read data with “char-read-hnd <hex handle>”, and write data with “char-write-cmd <hex handle> <new value>

First we enable the IR-Temperature service by writing “01” to handle “0x24”.

char-write-cmd 0x24 01

Then we enable read-notification for the IR-Temperature by reading from handle 0x21

char-read-hnd 0x21

Next we enable notification for the IR-Temperature by writing “01:00” to handle “0x22”

char-write-cmd 0x22 01:00

We will now start to see IR-Temperature data like

Notification handle = 0x0021 value: 4c 09 24 0b
Notification handle = 0x0021 value: 7c 09 28 0b
Notification handle = 0x0021 value: 6c 09 28 0b
Notification handle = 0x0021 value: 64 09 28 0b
Notification handle = 0x0021 value: 7c 09 28 0b
Notification handle = 0x0021 value: 6c 09 28 0b
Notification handle = 0x0021 value: 88 09 28 0b
Notification handle = 0x0021 value: 70 09 28 0b
Notification handle = 0x0021 value: 70 09 28 0b
Notification handle = 0x0021 value: 84 09 28 0b

And if we disable notifications by writing “00:00” to handle 0x22 the information will stop

char-write-cmd 0x22 00:00

##Summary for manual reading The gatttool is great, but to build a wrapper around it to use from Python or NodeJS is a lot of work. So lets be grateful for people like Sandeep Mistry and his sensortag library that provide functionality so that it becomes very easy to do the things we did manually above. It actually only takes a few lines of code.

#Setting up the Raspberry Pi for Real-Time communication Since the library we use the communicate with the sensortag from the Raspberrry Pi is based on NodeJS, we will use NodeJS for real-time communication as well.

##Installing NodeJS Installing nodejs on a Raspberry Pi is very easy.

sudo wget http://node-arm.herokuapp.com/node_latest_armhf.deb 
sudo dpkg -i node_latest_armhf.deb

Then you can verify the version by running (and this will probably output v0.12.0)

node -v

#The solution The mission with this article was to show how to read/write in full-duplex to CC2650 from anywhere in the world. To be able to do so we need three parts.

  1. A sensor client on the Raspberry Pi that communicates with the BLE device and also has a full-duplex connection to our real-time server.
  2. A real-time server that can dispatch messages to the clients monitoring the sensors as well as dispatching messages to the sensor client when the monitoring clients want to write data to the sensor.
  3. A monitoring client (can be several types) that display sensor data and send command to the sensor client via the real-time server.

These three implementation will be covered below.

##Sensor Client The sensor client (nodejs) on the Raspberry Pi is pretty easy to build.

Setup

Create a folder called CC2650 and navigate to it.

Install sensortag library

npm install sensortag

Install xsockets.net library

npm install xsockets.net

Code

The complete code for the client (~70 lines) can be found in the github repository, but the important parts is covered here. Just place the app.js file in the folder where you installed the packages above.

Connection to server, note that the ip and port here is used for development only. When deployed to Azure the IP and port will be replaced with the public endpoint.

//Connecting to XSockets
var conn = new xsockets.TcpClient('192.168.1.3', 4502, ['sensor']);
//Getting the sensorcontroller
//The controller is used to listen for data as well as sending data
var sensorcontroller = conn.controller('sensor');

When temperature changes on the sensortag

tagInstance.on('irTemperatureChange', function (ot, at) {
    //call server method 'irTempChange' and pass new value
   sensorcontroller.send('irtempchange', { obj: ot, amb: at });
});

When a monitoring client enables IR-Temperature

sensorcontroller.on('enableirtemp', self.enableIrTemperature);

When a monitoring client some where in the world disables the IR-Temperature

sensorcontroller.on('disableirtemp', self.disableIrTemperature);                                                           

##Real-Time Server Since XSockets.NET has state, can connect anything and allows you to talk cross-protocol etc it will be very easy to build the server-side communication.

Sensor Controller

This is the controller that the sensor client will use to send data to. The concept is simple yet efficient. When a sensor client send a message to the sensor controller, the message is dispatched to all clients having an instance of the monitor controller. This way all client monitoring will get notifications about

  • Sensors that connect/disconnect
  • Sensors that get IR-Temperature enabled/disabled
  • Changed in temperature on the sensor

enter image description here

Monitor Controller

The monitor controller is even simpler than the sensor controller. This only has three methods.

  • First one to be able to get information about all sensors being online (OnOpened).
  • Second one for disabling the IR-Temperature notifications on the sensor.
  • Third one for enabling the IR-Temperature on the sensor.

By passing in the connection id that we know from the sensor client the server can target the correct sensor to disable/enable.

enter image description here

##Monitoring Client Since you can connect anything to the real-time server (XSockets) you can control the sensor from pretty much anything. Your imagination sets the limits! In this sample I will only use a basic webpage and JavaScript to read/write data from the sensor.

Code

The complete code for the client can be found in the github repository, but the important parts is covered here.

Connection to server, note that the ip and port here is used for development only.

//Connecting to XSockets
var conn = new XSockets.WebSocket('ws://192.168.1.3:4502', ['monitor']);        
//Getting the monitorcontroller
//The controller is used to listen for data as well as sending data
var monitor = conn.controller('monitor');

When the server send notificaiton about temperature changes

monitor.on('irTempChange', function(d) {
    console.log('irtempchange', d);
    vm.update(d);
});

Enable the IR-Temperature from the webpage

monitor.invoke('enableIrTemp', vm.id());

Disable the IR-Temperature from the webpage

monitor.invoke('disableIrTemp', vm.id());

When a monitoring client some where in the world disables the IR-Temperature

monitor.on('irTempDisabled', function(id) {
    vm.disable(id);
});

When a monitoring client some where in the world enables the IR-Temperature

monitor.on('irTempEnabled', function(id) {
    vm.enable(id);
});

Up & Running

An image showing the result from my development machine. We see the sensor tag connected over BLE to a Raspberry Pi that uses NodeJS to communicate with XSockets. Then XSockets sends data to all clients, in this case just a webpage. We can also enable/disable the sensors services directly from the webpage (or any other client).

The "black" window is just the output from the Raspberry Pi connected via Putty. enter image description here

#Deploying to Azure To host this solution on Azure we need to create a Worker Role that will host the XSockets server. Since we already have our XSockets modules in a separate class library we just need to reference that assembly.

##Configuration To be able to connect to the server on Azure we need to start the server on atleast one public endpoint. ###Service Configuration Since we want to be able to run on localhost we configure both the "ServiceConfiguration.Local.cscfg" as well as the "ServiceConfiguration.Cloud.cscfg"

Local enter image description here

Cloud Note: you should of course replace "cc2650.cloudapp.net" with the uri you deploy to. enter image description here

###Service Endpoint We can run the server on multiple endpoints, but here we only setup port 8080. enter image description here So when the local config is used we run on 127.0.0.1:8080 and when the cloud config is used we run on cc2650.cloudapp.net:8080 ##Starting We will start the server in the "OnStart" method of the Worker Role, the extension method called "StartOnAzure" will create configurations based on the configuration combined with the service endpoint.

public override bool OnStart()
{
    bool result = base.OnStart();
    _container = Composable.GetExport<IXSocketServerContainer>();                       
    _container.StartOnAzure();            
    return result;
}

#Summary The biggest challenge (for me) when building this was to setup BLE on the Raspberry Pi, but the reason for that is probably my limited skills in Linux and BLE. The Raspberry Pi 2 is extremely great to work with and the Texas Instruments SensorTag is very stable and easy to use. I also want to give some credit to Azure since deploying XSockets on Azure was extremely easy.

What's next?

This post only uses the IR-Temperature service from the CC2650. I will continue to improve the solution and add support for more services as well as support for multiple SensorTags so that people around the world can register their own tags to be shown on Azure.

##Video A short video showing how to deploy and test the solution. [link here]

##GitHub Repository The complete solution is available on GitHub

#Resources

About

Controlling the Texas Instruments SensorTag (CC2650) from anywhere in the world